java异常
异常类
jvm异常处理机制
停止运行,显示异常信息
public class Test1 { public static void main(String[] args) { System.out.print(10/0); System.out.println(4); } } //结果:Exception in thread "main" java.lang.ArithmeticException: / by zero at com.sun.test.Test1.main(Test1.java:6) //最后打印4的语句根本没有执行,停止运行了。
异常的作用就是让编译成功的程序重新编译不成功,那么运行的时候程序就会出现错误,如果自己能解决就解决,不能解决jvm就来解决,让运行中止,并显示异常信息。
try catch
我们不能总是在程序出现错误的时候才解决问题,需要提前准备好,如果在100次中出现了1次异常怎么办。换句话说你这个程序别人用的100次中可能有一次出问题,那么你这个程序就是有问题的,不能怪别人。所以我们需要针对那一次错误让整个程序在任何时刻都是没有问题的。所以有这样的逻辑“当程序没有出现错误时正常运行。当程序出现错误时该程序不执行(捕获异常,然后换个正常的语句执行),换个程序执行”所以有try catch的出现。不想要jvm自动帮我们处理异常。
public class Test1 { public static void main(String[] args) { int a[]=new int[10]; a[0]=1; a[1]=5; a[3]=0; a[4]=5; System.out.print(a[1]/a[4]); } } //这样是没有问题的,最后结果是1
当碰到a[4]的值为0时,那就会报错了,所以需要捕获异常,不能让程序终止
public class Test1 { public static void main(String[] args) { int a[]=new int[10]; a[0]=1; a[1]=5; a[3]=0; a[4]=0; try { System.out.print(a[1]/a[4]); }catch(ArithmeticException e) { System.out.print("除数为0的错误"); }; } } //程序没有问题了
但是当数组下标一不小心写错了,那又有问题了,所以一个语句,我们需要考虑到两个异常
public class Test1 { public static void main(String[] args) { int a[]=new int[10]; a[0]=1; a[1]=5; a[3]=0; a[4]=0; try { System.out.print(a[1]/a[100]); }catch(ArithmeticException e) { System.out.print("除数为0的错误"); }; } } //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 // at com.sun.test.Test1.main(Test1.java:11)
public class Test1 { public static void main(String[] args) { int a[]=new int[10]; a[0]=1; a[1]=5; a[3]=0; a[4]=0; try { System.out.print(a[1]/a[100]); }catch(ArithmeticException e) { System.out.print("除数为0的错误"); }catch(ArrayIndexOutOfBoundsException e) { System.out.print("越界"); }; } } //这就没有问题了,解决了可能出现的两种异常
编译时异常
在编译时就将异常进行处理。只需要判断什么异常在编译时处理,什么异常在运行时处理即可。
编译时异常和运行时异常的区别:当你编写了除数为0的代码和没有编写除数为0的代码,运行时异常在后者不会出现,程序正常运行,在前者会出现异常。当你编写遇到编译时异常的程序时,即使你的代码一点问题也没有,在逻辑上能正常通过,它编译时也不让你通过。总结一下在运行时100个程序,有一个出现错误,能通过99个;在编译时有100个程序,有一个出现错误,能通过0个。其实编译和运行时处理异常都一样,反正都要捕获异常。
这个事情做多了也就知道为什么要分这两种异常了(存在即合理的)
抛异常
前面所接触的是捕获异常,捕获的异常都是别人创建的异常对象,我们可以自己new一个异常对象,然后抛异常,就是为了让程序出错时无法继续运行。(即让程序的调用者自己处理异常)
public class Person { public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) throws Exception{ if(age>0&&age<100) this.age = age; else throw new Exception("年龄非法"); } public String name; public int age; }
public class Test2 { public static void main(String[] args) throws Exception { Person p=new Person(); p.setAge(-10); System.out.print(p.getAge()); } } //Exception in thread "main" java.lang.Exception: 年龄非法 at com.sun.test.Person.setAge(Person.java:17) at com.sun.test.Test2.main(Test2.java:6)
finally
finally的作用就是有这么‘一个情况,当程序正常运行和不正常运行的最终执行的都有一个相同程序,这个程序不管前面是处理异常还是没有处理异常都必须得执行。
那如果按这样说,我们直接在try catch语句结束后加一条语句不就行了吗
public class Test3 { public static void main(String[] args) { try { System.out.println(10/0); }catch(Exception e) { System.out.println("出错啦"); }; System.out.println("必须执行的"); } } //出错啦 //必须执行的
public class Test3 { public static void main(String[] args) { try { System.out.println(10/2); }catch(Exception e) { System.out.println("出错啦"); }; System.out.println("必须执行的"); } } //5 //必须执行的
这样不也可以吗,但是有这样的一个情况(下面的情况cath语句中结束了程序的执行,后面打印的结果没法执行)
public class Test3 { public static void main(String[] args) { try { System.out.println(10/0); }catch(Exception e) { System.out.println("出错啦"); return ; }; System.out.println("必须执行的"); } } //出错啦
所以finally的作用就是不管你代码是什么,都不会影响我finally代码的运行
public class Test3 { public static void main(String[] args) { try { System.out.println(10/0); }catch(Exception e) { System.out.println("出错啦"); return ; }finally{ System.out.println("必须执行的"); }; } } //出错啦 //必须执行的
自定义异常
观察API,除了Throwable类,其他继承的异常类的方法都是继承Throwable类的。所以异常的区分只是区分名字而已
总结
对于异常的处理,先要找到异常(先发现异常),当你写程序时编译或者运行出现的异常,然后再进行异常处理。我们针对的是异常,不是处理事务的逻辑。