Java基础 - 异常
1. 异常的分类
1.1 Throwable
Java中所有的异常都继承自java.lang.Throwable这个类表示可抛出的
Throwable这顶级父类的常用方法:
1. 返回异常发生时的详细信息
public string getMessage();
2. 返回异常发生时的简要描述
public string toString();
3. 返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
public string getLocalizedMessage();
4. 在控制台上打印Throwable对象封装的异常信息
public void printStackTrace();
1.2 Exception和Error
Exception和Error这是Thorwable的两个重要的子类:
Exception表示异常,Error表示错误

1.2.1 Error
定义:
程序无法处理的错误,表示程序运行中出现较为严重的问题;
通常有: VirtualMachineError(虚拟机错误),比如说当jvm耗完可用内存时,将出现OutOfMemoryError(OOM)
此类错误发生时,JVM一般会终止线程,
1.2.2 Exception
定义:
程序本身可以处理的异常;
分类:
- 运行时异常:(RuntimeException)这一类异常,在编写代码时,可以不捕获;例如:
NullPotinterException(空指针异常)- 非运行时异常: 这一类异常,在编写代码时,必须要捕获,否则编译不过去;例如:
FileNotFoundException(文件未找到异常)
2. 异常的处理
2.1 抛出 Throw、Thorws
2.1.1throw
throw关键字使用在方法内部,将异常丢出去,程序执行到这一步,会报错误,throw一旦进入被执行,程序立即会转入异常处理阶段,后面的语句就不再执行,而且所在的方法不再返回有意义的值!
public void m1(){
if(a > 0){
throw new NullPointerException();
}
}
2.1.2 throws
throws关键字使用在方法上,将程序丢给调用者如果一个方法里面不想有任何的异常处理,则在没有任何代码进行异常处理的时候,必须对这个方法进行声明有可能产生的所有异常
(其实就是,不想自己处理,那就交给别人吧,告诉别人我会出现什么异常,报自己的错,让别人处理去吧)
如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。
例如汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。
public void m1() throws NullPointException,FileNotFoundException{
}
- 需要注意的是:
- throw 是自己处理异常
- throws 是将异常丢给调用者
2.2 捕获 try
语法:
try { // 可能会发生异常的程序代码 } catch (Type1 id1){ // 捕获并处置try抛出的异常类型Type1 } catch (Type2 id2){ //捕获并处置try抛出的异常类型Type2 }finally { // 无论是否发生异常,都将执行的语句块 }执行顺序:
try、catch、finally语句块的执行顺序:
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句。注意: finally不执行的情况
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。
在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
3. 自定义异常
自定义异常格式:
public class MyException extends RuntimeException {
public MyException() {
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/*
a.输出异常的信息
getMessage()
b.输出导致异常更为详细的信息
printStackTrace()
*/
4. try...catch...finally
关于try...catch...finally执行顺序
1. 只在try中返回
public static int m1() {
int a = 10;
try {
System.out.println("try - " + a);
return a;
} catch (Exception e) {
System.out.println("catch - " + a);
return a = 20;
} finally {
a = 15;
System.out.println("finall - " + a);
}
}
public static void main(String[] args) {
System.out.println("main - " + m1());
}
/*
执行结果:
try - 10
finall - 15
main - 10
*/
语句在finally中执行了,但是没有将a的值更改。
解释:
代码顺序执行从try到finally,由于finally是无论如何都会执行的,所以try里的语句并不会直接返回。 在try语句的return块中,return返回的引用变量并不是try语句外定义的引用变量a,
而是系统重新定义了一个局部引用a1,这个引用指向了引用a对应的值,也就是10,即使在finally语句中把引用a指向了值15,
因为return返回的引用已经不是a,而是a1,所以引用a的值和try语句中的返回值无关了。
2. 在finally中也返回
public static int m1() {
int a = 10;
try {
System.out.println("try - " + a);
return a;
} catch (Exception e) {
System.out.println("catch - " + a);
return a = 20;
} finally {
a = 15;
System.out.println("finall - " + a);
return a;
}
}
public static void main(String[] args) {
System.out.println("main - " + m1());
}
/*
执行结果:
try - 10
finall - 15
main - 15
*/
-- 这里是将 返回值更改了
可以看到,是从finally语句块中返回的。可见,JVM是忽略了try中的return语句
3. 返回值是数组或是集合
public static List m1() {
List<String> strList = new ArrayList<>();
try {
strList.add("try");
System.out.println("try - ");
return strList;
} catch (Exception e) {
strList.add("catch");
System.out.println("catch - ");
return strList;
} finally {
strList.add("finally");
System.out.println("finall - ");
return strList;
}
}
public static void main(String[] args) {
System.out.println("main - " + m1());
}
/*
执行结果:
try -
finall -
main - [try, finally]
*/
4. 总结:
1、finally语句总会执行
2、如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响(包装类型、静态变量会改变、*全局变量*)
3、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生
4、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略
所以在实际项目中,finally常常是用来关闭流或者数据库资源的,并不额外做其他操作。

浙公网安备 33010602011771号