异常
异常(Exception)是Java中的一个类,异常类有很多的子类但总体分为两大类,编译时异常和运行时异常。
编译时异常是指程序在编译阶段就会进行检验,判断代码是否有可能会出现问题,虽然程序是没有问题的但是可能由于某种变量出现问题而导致出现异常,就比如Class.forName("")方法用于查找指定的类传入一个字符串形式的全类名,这时程序就会出现编译时异常,因为我们传入的参数可能会出现找不到该类等等的问题,所以程序问了防止出现这种异常的情况会让我们对可能出现这种问题的情况进行预处理,这就是编译时异常。
运行时异常是指代码没有任何问题但是在程序运行的过程中出现了异常的情况,就比如一个长度为2的数组,如果你想要获取下标为2的数组中的元素那么虽然代码在编译阶段没有报错,那是因为数组在编译的阶段并不会检验给出的下标是否超过了数组的长度,它只是会判断给出的下标是否为数字,只有在程序运行的阶段数组才会调用方法取判断数组本身的长度以及给出的下标,所以这种异常的出现得要靠程序员的经验去解决程序员如果考虑的比较方方面面那么就可以使用try、catch以及finally等的关键字避免运行时异常的发生。
try关键字
try关键字放在代码块的前面表示该代码块中的代码可能会出现异常。
int a = 10;
int b = 0;
try {
int c = a / b;
}
catch关键字
catch关键字放在代码块的前面不能单独出现只能和try关键字一起使用,表示如果try关键字修饰的代码块中的代码如果出现了异常,catch代码块需要进行的操作并且catch代码块有一个参数表示出现的异常的类型,当可能出现的异常有多个时catch代码块可以有多个来表示不同的异常会进行不同情况的处理。
int a = 10;
int b = 0;
String s = null;
try {
int c = a / b;
s.length();
} catch (ArithmeticException e) {// 可以定义多个异常类型但是范围是从小到大的
e.printStackTrace();
System.out.println("ArithmeticException异常");
} catch (NullPointerException e) {
e.printStackTrace();
System.out.println("NullPointerException异常");
}
finally关键字
finally关键字修饰的代码块不能单独出现只能和try关键字一起使用, finally代码块中的代码不管try代码块中是否出现了异常都会被执行。
throws关键字
throws关键字用于对方法的声明,表示该方法中可能会出现的异常的类型,如果出现异常就将异常抛出给调用该方法的方法而不做处理,但是main方法不能对方法进行抛出如果main方法也将异常抛出给虚拟机,虚拟机是不会做处理的所以程序就会报错。抽象方法也可以使用throws关键字进行声明,子类在实现抽象方法时如果选择抛出异常,那么抛出异常的范围一定得是等于或者小于抽象方法抛出的异常,假设父类抽象方法抛出的是IoException那么子类抛出的异常类型可以是IoException,也可以是IoException的子类。
throw关键字
throw关键字用于主动地抛出异常对象,在一个被调用的方法中如果出现了异常并且我们无法通过返回值告诉调用该方法的方法出现了异常,那么就可以使用throw关键字抛出一个异常对象将该异常抛给上一级方法,由于该方法没有对异常进行处理所以需要使用throws关键字声明该方法,将异常交给上一级方法进行处理。
throw关键一般用于自定义的异常类中,当我们主动地抛出异常对象但是并不是所有异常都存在与类库中,这时我们就可以自定义异常类。
首先创建自定义异常类如果为编译时异常就需要继承Exception,如果为运行时异常就需要继承RuntimeException,一般我们都会选择为编译时异常因为运行时异常在编译阶段是没有任何提示的。
public class ScoreException extends Exception {// 自定义异常类并重写构造方法
public ScoreException() {
super();
}
public ScoreException(String message) {
super(message);
}
}
测试代码
public class Test {
public static void main(String[] args) {
char res = ' ';
try {
res = test(101);
} catch (ScoreException e) {
System.out.println(e.getMessage());
}
System.out.println(res);
}
public static char test(int score) throws ScoreException {
if (score > 100 || score < 0) {
throw new ScoreException("成绩不合法");
}
return '良';
}
}
关键字组合
try、catch
String s = null;
try {// 代码块中可能会出现异常
s.length();
} catch (NullPointerException e) {// 对异常进行的处理
e.printStackTrace();
System.out.println("NullPointerException异常");
}
try、finally
public static void main(String[] args) {
try {// 代码块中出现异常
test();
} catch (NullPointerException e) {// 对异常进行处理
System.out.println("NullPointerException异常");
}
}
public static void test() {
String s = null;
try {// 代码块中可能会出现异常
s.length();
} finally {// 没有对异常进行处理,将异常抛给了上一级方法
System.out.println("finally代码块");
}
System.out.println("123");
}
try、catch、finally
public static void main(String[] args) {
int num = test(null);
System.out.println(num);
}
public static int test(String s) {
try {// 代码块中可能会出现异常
s.length();
return 0;
} catch (NullPointerException e) {
System.out.println("NullPointerException异常");
return -1;
} finally {//当方法中存在返回值,不会先执行return,而是会先执行finally代码块中的代码,然后再返回
System.out.println("finally代码块");
}
}
当方法中既存在return又存在finally代码块,程序会先将return需要返回的值进行保存,然后去执行finally代码块中的代码,当代码块中的代码执行完毕后,再将先前保存的需要返回的值进行返回。
所以说一般不建议在finally代码块中添加return语句,如果在执行finally代码块之前已经将return需要返回的值进行了保存,那么在执行finally代码块时,如果代码块中也存在return语句,值就会提前返回,导致返回的值与原来进行保存的不一样,导致数据出现错误。