1.什么是异常?
异常就是Java程序在运行过程中出现的错误。
2.异常的继承体系
java.lang.Object
java.lang.Throwable
java.lang.Error
java.lang.Exception
java.lang.RuntimeException
RuntimeException是在Java虚拟机的正常操作期间可以抛出的那些异常的超类。而除了RuntimeException,其他类是编译时异常。
- 运行时异常与编译时异常有什么区别呢?
所有的RuntimeException类以及其子类的实例被称为运行时异常,其他的异常就是编译时异常
编译时异常:java程序必须显示处理,否则程序就会发生错误,无法通过编译。常见的编译时异常就是打开文件时,必须在编译的时候处理。如果不处理异常,编译通不过。
运行时异常:无需显示处理。运行时异常是代码错误,需要回头更改代码。
3.异常的检测、捕获
(1) try ... catch
(2) try ... catch ... finally
(3) try ... finally
try用来检测异常的,catch用来捕获异常的,finally用来释放资源的。
public static void main(String[] args) { try{ int num = 10/0; }catch (Exception e){ System.out.println("除数不能为0"); }finally { System.out.println("我会不会执行?"); } } // 输出结果: 除数不能为0 我会不会执行?
4.打印异常信息
Throwable的几个常见的方法:
(1) getMessage() 获取异常信息,返回字符串
(2) toString() 获取异常类名和异常信息,返回字符串
(3) printStackTrace 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值为void。(jvm默认方式)
public static void main(String[] args) { try{ int num = 10/0; }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("我会不会执行?"); } } // 输出结果: java.lang.ArithmeticException: / by zero at com.pr.Test15.main(Test15.java:6) 我会不会执行?
5.主动抛出异常
例如有一个学生类,有两个属性,姓名与年龄。其中年龄需要合法的年龄。这时候可以利用主动抛出异常来避免年龄非法了。
public void setAge(int age) { if (this.age > 0 && this.age < 150){ this.age = age; }else { throw new RuntimeException("年龄不合法"); }
抛出RuntimeException,运行时异常。看一下跑出编译时异常的写法:
public void setAge(int age) throws Exception { if (this.age > 0 && this.age < 150){ this.age = age; }else { throw new Exception("年龄不合法"); }
可以看到我们需要在方法上面声明,这个方法有异常抛出,你用我的时候,要捕获异常(可以try ... catch 也可以直接 throws)。
总结1:编译时异常的抛出必须对其进行处理
运行时异常的抛出可以处理也可以不处理
总结2:throw与throws的区别
throw:用在方法体内,跟的是异常对象名 。只能抛出一个异常对象名。表示抛出异常,由方法体内的语句处理。
throws:用在方法声明后面,跟的是异常类名。可以跟多个异常类名,用逗号隔开。表示抛出异常,由该方法的调用者来处理。
6.关于finally
finally里面的代码无论是否发生异常都会执行。关于finally,遇到一道很有意思的题:
public static void main(String[] args) { try{ System.out.println(10/0); }catch (Exception e){ return; }finally { System.out.println("flag"); } }
catch里面有return,会不会输出flag呢?结果是输出flag。这样是不是意味者先执行System.out.println("flag"),然后再执行return呢?
再看一道题:
public class Test16 { public static void main(String[] args) { System.out.println(Demo.test()); } } class Demo{ public static int test(){ int i = 10; try{ i = 20; System.out.println(10/0); return i; }catch (Exception e){ i = 30; return i ; }finally { i = 40; } } }
按照上面的逻辑,输出结果应该是40。但是真实的运行结果是30。为什么呢?
其实在运行到catch的时候,i 赋值为30,然后return i 给 i 建立了返回的通道,然后再执行finally语句,最后 return 。
7.自定义异常
class AgeOutOfRangeException extends Exception{ public AgeOutOfRangeException() { } public AgeOutOfRangeException(String message) { super(message); } }
8.异常注意事项
(1)子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。
(2)如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
(3)如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws