异常
异常是什么?
- 异常是代码在编译或者执行的过程中可能出现的错误。
- 避免异常的出现,同时处理可能出现的异常,让代码更稳健。
异常分为几类?
- 编译时异常、运行时异常。
- 编译时异常:没有继承RuntimeExcpetion的异常,编译阶段就会出错。
- 运行时异常:继承自RuntimeException的异常或其子类,编译阶段不报错,运行可能报错。
异常的体系
-
Error:
- 代表的系统级别错误(属于严重问题).
-
Exception:叫异常,分为两类: 编译时异常, 运行时异常
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
-
JVM默认如何处理异常?
-
打印异常信息
立即结束程序(异常出现后,如果不处理,程序是无法继续向下运行的)
-
-
直接抛出
- 异常需要被调用者知道,就需要把异常抛出
throws Exception
- 异常需要被调用者知道,就需要把异常抛出
-
捕获异常
-
如果方法中出现的异常, 不需要调用者知道, 需要为异常进行处理解决, 就可以使用捕获异常
try catch后的代码会继续执行
抛出异常
- 在Java的方法调用中,如果一个方法中出现了异常,本方法自己不处理,默认是会抛给调用方法去处理的
- 此时要注意的是,如果发生的是非运行时异常,需要在方法上明确使用throws关键字声明抛出
方法 throws 异常1 ,异常2 ,异常3 ..{ … }
// 推荐方式
方法 throws Exception{ }
// Exception代表可以捕获一切异常
B方法 -> A方法 -> main
捕获异常
- 直接在当前方法,发生异常的代码外使用try–catch–结构捕获并处理异常
- 异常处理后,后续的代码是可以继续执行的
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
// 推荐方式
try{
// 可能出现异常的代码!
}catch (Exception e){
e.printStackTrace(); // 直接打印异常对象的信息
}
// Exception代表可以捕获一切异常
B方法 -> A方法 -> main
自定义异常
运行时异常 | 自定义异常 |
---|---|
定义一个异常类继承RuntimeException | 定义一个异常类继承Exception |
重写构造器 | 重写构造器 |
通过throw new 异常类(xxx)来创建异常对象并抛出 | 通过throw new 异常类(xxx)来创建异常对象并抛出 |
编译阶段不报错,提醒不强烈,运行时才可能出现!! | 编译阶段就报错,提醒更加强烈!! |
运行时异常的特点 | 编译时异常的特点 |
---|---|
运行时异常:继承自RuntimeException的异常或者其子类 | 编译时异常:继承自Exception的异常或者其子类 |
编译阶段不报错,运行可能报错。 | 编译阶段报错,必须处理,否则代码不通过。 |
默认异常处理机制 | 默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡! |
---|---|
异常的处理形式 | 运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以; 按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。 |
自定义编译时异常 | 定义一个异常类继承Exception; 重写构造器; 在出现异常的地方用throw new 自定义对象抛出; 作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!! |
异常处理的总结 | 作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理; 实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。 |
Lambda表达式
Lambda表达式是JDK 8开始新增的一种语法形式; 作用:用于简化匿名内部类的代码写法。
(被重写方法的形参列表) -> {
被重写方法的方法体代码。
}
Lambda表达式只能简化
函数式接口的匿名内部类!!!
new 类或接口(参数值…) {
方法实现(被重写方法的形参列表){
被重写方法的方法体代码
}
};
什么是函数式接口?
- 有且仅有一个抽象方法的接口。
- 注意:大部分函数式接口上面都会有一个@FunctionalInterface的注解,有该注解的接口就必定是函数式接口。
Lambda表达式的省略写法(进一步简化Lambda表达式的写法)
- 参数类型可以省略不写
- 如果只有一个参数,小括号()也可以省略。
- 如果Lambda表达式中的方法体代码只有一行代码,可以省略花括号{}不写,同时要省略分号!此时,如果这行代码是return语句,也必须去掉return不写。
方法引用
静态方法的引用
语法 类名::静态方法
场景 如果某个Lambda表达式里只是调用一个静态方法,并且前后参数的形式一致,就可以使用静态方法引用。
实例方法的引用
语法 对象名::实例方法
场景 如果某个Lambda表达式里只是调用一个实例方法,并且前后参数的形式一致,就可以使用实例方法引用。
特定类型的方法引用
语法 类型::方法
场景 如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
构造器引用
语法 类名::new
场景 如果某个Lambda表达式里只是在创建对象,并且前后参数情况一致,就可以使用构造器引用。
Integer[] ages={66,44,87,34};
Arrays.sort(ages, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
System.out.println("内容: "+ Arrays.toString(ages));
Integer[] ages={66,44,87,34};
Arrays.sort(ages, (o1, o2) -> o2-o1);
System.out.println("内容: "+ Arrays.toString(ages));
注意:通常我们见到的函数式接口上都有一个@Functionallnterface注解,
标记该接口必须是满足函数式接口。
Lambda表达式简化按钮监听器ActionListener的匿名内部类形式
JButton btn = new JButton("登录");
//给登录按钮绑定点击事件监听器
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("登录一下~~~");
}
});
JButton btn = new JButton("登录");
//给登录按钮绑定点击事件监听器
btn.addActionListener(e -> System.out.println("登录一下~~~"));
-
Lambda表达式的省略写法(进一步在Lambda表达式的基础上继续简化)
-
参数类型可以省略不写。
-
如果只有一个参数,参数类型可以省略,同时()也可以省略。
-
如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写,同时要省略分号!
-
如果Lambda表达式的方法体代码只有一行代码。可以省略大括号不写。此时,如果这行代码是return语句,必须省略return不写,同时也必须省略";"不写
-
常见算法
排序算法
冒泡排序
每次比较两个相邻的元素,小的放左边大的放右边
实现冒泡排序的关键点分析
确定总共需要做几轮: 数组的长度-1.
每轮比较几次:i(第几轮) 比较位 次数规律: 数组的长度 – i -1
0 0 1 2 (3次)
1 0 1 (2次)
2 0 (1次)比较规则: 相邻两个元素比较,大的放在右边
-
冒泡排序的思想
- 从头开始两两比较,把较大的元素与较小的元素进行交换
- 每轮把当前 最大的一个元素存入到数组当前的末尾。
-
冒泡排序的实现步骤。
-
定义一个外部循环控制总共需 要冒几轮(数组的长度-1)
-
定义一个内部循环, 控制每轮依次往后比较几个位置(数组长度-i-1)
-
如果当前位置的元素值>后- 一个位置的元素值,两者交换。
public class Test5冒泡排序 { public static void main(String[] args) { // 1、定义一个数组,存储一些数据啊 int[] arr=new int[4]; Scanner sc=new Scanner(System.in); for (int i = 0; i < arr.length; i++) { System.out.println("请输入第" + (i+1) + "个数据"); arr[i]=sc.nextInt(); } // 2、定义一个循环控制比较的轮数 //for (int i = 1; i <= arr.length-1; i++) { for (int i = 0; i < arr.length-1; i++) { // i == 0 比较的次数 3 j = 0 1 2 // i == 1 比较的次数 2 j = 0 1 // i == 2 比较的次数 1 j = 0 // 3、定义一个循环控制每轮比较的次数,占位 //for (int j = 0; j < arr.length-i; j++) { for (int j = 0; j < arr.length-i-1; j++) { // 判断j当前位置的元素值 是否 大于后一个位置 若较大 则交换 if (arr[j]>arr[j+1]){ int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + "\t"); } } }
-
选择排序
选择排序算法
每轮选择当前位置, 开始找出后面较小值与该位置交换
选择排序的关键
确定总共需要几轮: 数组的长度减一
控制每轮从以前的位置为基准, 与后面元素选择几次
二分查找
-
数组的二分查找的实现步骤是什么样的?
-
定义变量记录左边和右边位置。
-
使用while循环控制查询(条件是左边位置<=右边位置)
-
循环内部获取中间元素索引
-
判断当前要找的元素如果大于中间元素,左边位置=中间索引+1
-
判断当前要找的元素如果小于中间元素,右边位置=中间索引-1
-
判断当前要找的元素如果等于中间元素,返回当前中间元素索引。
-
正则
String类的哪个方法可以与正则表达式进行匹配。
public boolean matches(String regex):
判断是否匹配正则表达式,匹配返回true,不匹配返回false。
正则表达式在字符串方法中的使用
方法名 | 说明 |
---|---|
public String replaceAll(String regex,String newStr) | 按照正则表达式匹配的内容进行替换 |
public String[] split(String regex): | 按照正则表达式匹配的内容进行分割字符串,反回一个字符串数组。 |
正则表达式支持爬取信息