Java 异常处理
1. 异常概述
1. Error: Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
2. Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针访问、试图读取不存在的文件、网络连接中断
2.1 编译时异常:在编译期间会出现的异常(执行javac.exe命令时,出现异常)
2.2 运行时异常:在运行期间出现的异常(执行java.exe命令时,出现异常)
对于编译时异常来说,必须要显式的进行处理。
对于运行时异常来说,可以不显式的进行处理。
常见的运行时异常:java.lang.RuntimeException
数组下标越界的异常:ArrayIndexOutOfBoundsException
算术异常:ArithmeticException
类型转换异常:ClassCastException
空指针异常:NullPointerExcetion
2. 如何处理Exception的异常
Java提供的是异常处理的抓抛模型
1."抛":当我们执行代码时,一旦出现异常,就会在异常的代码处生成一个对应的异常类型的对象,并将此对象抛出。(自动抛出 / 手动抛出)
>一旦抛出此异常类的对象,那么程序就终止执行
>此异常类的对象抛给方法的调用者。
2."抓":抓住上一步抛出来的异常类的对象。如何抓?即为异常处理的方式
java 提供了两种方式用来处理一个异常类的对象。
处理的方式一:
try{ //可能出现异常的代码 }catch(Exception1 e1){ //处理的方式1 }catch(Exception2 e2){ //处理的方式2 }finally{ //一定要执行的代码 }
注:1.try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
2.finally是可选的。
3.catch语句内部是对异常对象的处理:
>getMessage(); printStackTrace();
4.可以有多个catch语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足就执行catch中的代码。执行完,就跳出其后的多条catch语句
5.如果异常处理了,那么其后的代码继续执行。
6.若catch中多个异常类型是"并列"关系,孰上孰下都可以。
若catch中多个异常类型是"包含"关系,须将子类放在父类的上面,进行处理。否则报错!
7.finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句。
8.try-catch是可以嵌套的。
异常处理的方式二:在方法的声明处,显式的抛出该异常对象的类型
格式:如:public static void method2() throws FileNotFoundException,IOException{}
当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。
异常的对象可以逐层向上抛,直至main中。当然在向上抛的过程中,可以再通过try-catch-finally进行处理。
3. java的异常处理:抓抛模型
1.抓:异常的处理,有两种方式(①try-catch-finally ② throws + 异常的类型)
2.抛:一旦执行过程中,出现异常,会抛出一个异常类的对象。(自动的抛出 vs 手动的抛出(throw + 异常类的对象))
>异常类,既可以是现成的异常类,也可以是自己创建的异常类
抛出的异常类型:若是RuntimeException,可以不显式的处理
若是一个Exception,必须要显式的处理。
4. 如何自定义一个异常类
1.自定义的异常类继承现有的异常类
2.提供一个序列号,提供几个重载的构造器
public class MyException extends RuntimeException{ static final long serialVersionUID = -70348975766939L; public MyException(){ } public MyException(String msg){ super(msg); } }
public int compareTo(Object obj) throws Exception{ if(this == obj){ return 0; } else if(obj instanceof Circle){ Circle c = (Circle)obj; if(this.radius > c.radius){ return 1; }else if(this.radius == c.radius){ return 0; }else{ return -1; } }else{ //return -2; //手动的抛出一个异常 //throw new RuntimeException("传入的类型有误!"); throw new MyException("传入的类型有误!"); } }
5. 抛异常的方法的重写规则
子类重写的父类的方法,其抛出的异常类型只能是被重写的方法的异常类的子类或异常类型一样。
public class TestOverride { public static void main(String[] args) { A a = new B(); try { a.method1(); } catch (IOException e) { e.printStackTrace(); } } } class A { public void method1() throws IOException { } } class B extends A { public void method1() throws FileNotFoundException { } }
编译时,看的是左边,运行时,如果异常比父类的大,此异常处理不了。
6. 异常总结
练习:判断程序的输出结果
public class ReturnExceptionDemo { static void methodA() { try { System.out.println("进入方法A"); throw new RuntimeException("制造异常"); } finally { System.out.println("用A方法的finally"); }} static int methodB() { try { System.out.println("进入方法B"); return 1; } finally { System.out.println("调用B方法的finally"); return 2; }} public static void main(String[] args) { try { methodA(); } catch (Exception e) { System.out.println(e.getMessage()); } int i = methodB(); System.out.println(i); } } /* 进入方法A 用A方法的finally 制造异常 进入方法B 调用B方法的finally 2 */
练习:
/* * 编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。 对数据类型不一致(NumberFormatException)、缺少命令行参数(ArrayIndexOutOfBoundsException、 除0(ArithmeticException)及输入负数(EcDef 自定义的异常)进行异常处理。 提示: (1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。 (2)在main()方法中使用异常处理语句进行异常处理。 (3)在程序中,自定义对应输入负数的异常类(EcDef)。 (4)运行时接受参数 java EcmDef 20 10 //args[0]=“20” args[1]=“10” (5)Interger类的static方法parseInt(String s)将s转换成对应的int值。如int a=Interger.parseInt(“314”); //a=314; */ public class EcmDef { public static void main(String[] args) { try{ int i = Integer.parseInt(args[0]);//被除数 int j = Integer.parseInt(args[1]);//除数 ecm(i,j); }catch(NumberFormatException e){ System.out.println("输入的数据类型不一致"); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("缺少命令行参数"); }catch(ArithmeticException e){ System.out.println("分母为零了"); }catch(EcDef e){ System.out.println(e.getMessage()); } } public static void ecm(int i,int j) throws EcDef{ if(i < 0 || j < 0){ throw new EcDef("您输入的数值存在负数!"); } System.out.println(i / j); } } //自定义异常类 class EcDef extends Exception{ static final long serialVersionUID = -3387524229948L; public EcDef(){ } public EcDef(String msg){ super(msg); } }