Java系列(十二)__Java异常处理

Java系列(十二)__Java异常处理

本次所讲解的内容没有人会说难,如果你还说难,只能表示一个结果,此处省略十个字。。。

1.1、认识异常(了解)

         异常指的是导致程序中断的一种指令流。那么下面先通过两个程序来比较程序出现异常与没有出现异常的区别。

范例:程序不出现异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   System.out.println("2、除法计算:" + (10 / 2)) ;

                   System.out.println("3、除法计算结束。") ;

         }

}

1、除法计算开始。

2、除法计算:5

3、除法计算结束。

         此时程序没有出现任何的异常,所以可以正常执行完毕。

范例:程序出现异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                  System.out.println("2、除法计算:" + (10 / 0)) ;  è 此处出错之后,此行和之后的所有行都不执行

                   System.out.println("3、除法计算结束。") ;

         }

}

1、除法计算开始。

Exception in thread "main" java.lang.ArithmeticException: / by zero

        at TestDemo.main(TestDemo.java:4)

         现在发现程序一旦出现了异常,将导致程序的中断执行,那么现在的问题是,即使出现了异常,我们也希望程序可以正常执行完毕。

1.2、处理异常(重点)

         如果在异常出现之后也希望程序可以正常的执行完毕,那么在Java里面就可以采用如下的代码结构来进行异常的处理操作。主要使用三个关键字:try、catch、finally。

try {

         // 有可能出现异常的代码

} [ catch (异常类型 对象) {

         异常处理代码 ;

} catch (异常类型 对象) {

         异常处理代码 ;

} ... ] [finally {

         不管是否有异常都要执行

}]

范例:处理异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try{

                            System.out.println("2、除法计算:" + (10 / 0)) ;

                            System.out.println("******************") ;  // 异常出现之后的代码都不执行

                  } catch (ArithmeticException e) {

                            System.out.println("出现异常:" + e) ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         此时程序出现异常之后,发现将直接跳转到catch之中进行处理,处理完成之后,程序正常结束。

范例:使用finally作为程序的出口

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            System.out.println("2、除法计算:" + (10 / 0)) ;

                            System.out.println("******************") ;

                   } catch (ArithmeticException e) {

                            System.out.println("出现异常:" + e) ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         对于finally暂时先有个了解,此部分代码是日后讲解的第五个代码模型的组成部分。

         但是在进行异常信息输出的时候,如果直接输出异常对象,那么只是告诉了用户是什么异常,但是异常的信息并不完整,那么如果希望异常的信息完整,可以调用异常类之中的“printStackTrace()”方法进行详细输出。

catch (ArithmeticException e) {

         e.printStackTrace() ;

}

         在之前给出的格式之中,发现可以在一个try语句之后跟上多个catch语句,那么下面就来观察此类操作。

范例:现在希望通过初始化参数,来输入两个计算的数字

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                           int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" +(x / y)) ;

                            System.out.println("******************") ;

                   }catch (ArithmeticException e) {

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         那么现在的程序就有可能出现下面的问题:

                   · 问题一:执行的时候没有输入参数(Java TestDemo),ArrayIndexOutOfBoundsException,未处理;

                   · 问题二:输入的参数不是数字(java TestDemo a b),NumberFormatException,未处理;

                   · 问题三:输入数据的被除数是零(java TestDemo 10 0),ArithmeticException,已处理。

         那么现在发现程序之中,如果某些异常没有进行处理,那么程序依然会中断执行。所以就必须使用多个catch捕获。

范例:使用多catch操作

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                            int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" + (x / y)) ;

                            System.out.println("******************") ;

                   } catch (ArithmeticException e) {

                            System.out.println("〖ArithmeticException,算术异常。〗") ;

                            e.printStackTrace() ;

                   } catch (ArrayIndexOutOfBoundsException e) {

                            System.out.println("ArrayIndexOutOfBoundsException,数组越界异常。") ;

                            e.printStackTrace() ;

                   } catch (NumberFormatException e) {

                            System.out.println("NumberFormatException,数据转换异常。") ;

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         此时已经可以成功的进行所有异常的处理。但是所有的异常都是经过了大量的分析之后才可以得出的处理方案,那么既然都已经分析完了,直接写几个if..else判断要比使用try…catch更加简单,那么异常处理有什么用呢?

1.3、异常的处理流程(重点)

         Java之中之所以会提供异常处理机制,主要的目的就是希望可以减少用户的if..else判断,所以来讲以上的处理方案只是一种严格的方案。那么如果说现在某些代码分析起来比较麻烦,希望可以通过一些简单的方式进行异常处理的话,那么之前所编写的多个catch就不这么好用了。那么下面就需要针对于异常做一个流程的说明。

         那么如果要想解决异常问题,首先来看一下关于异常的继承结构:

ArithmeticException:

NumberFormatException:

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.ArithmeticException

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.IllegalArgumentException

               |- java.lang.NumberFormatException  

         发现所有的异常都继承了Throwable类,而这个类指的就是抛出信息的操作类。在这个类之中发现有以下两个子类:

         (面试题:请解释Error和Exception的区别?

                   · Error:表示的是JVM系统出错,此时程序还没有执行,所以用户不能处理;

                   · Exception:表示的是所有程序运行过程之中出现的异常,用户可以进行处理。

         那么一般而言,由于Throwable表示的范围太大了,那么程序之中处理的往往不会是Throwable,而都是Exception。按照之前对象的向上转型自动完成的概念上来讲,所有的子类对象都可以使用父类接收,那么就表示所产生出来的所有异常应该都是Exception的子类,所有的异常对象都应该可以自动转为Exception。

面试题:请解释异常的处理流程


1、   当程序在运行过程之中产生了异常之后,那么会自动由JVM根据产生的异常类型,自动实例化一个与之相匹配的异常类对象(对象可以进行引用传递,可以包含很多的信息);

2、   此时JVM会判断在出现异常的代码之中是否存在有try语句进行异常的捕获;

3、   如果现在存在有try语句,则会由try捕获异常类的实例化对象,如果没有try,那么表示没有异常处理,则会将异常交给JVM采用默认的处理方式

4、   如果此时存在有try,那么会由try捕获异常,而后与try语句之后的每一个catch进行匹配,如果当前catch不匹配,则会交给后面的catch继续匹配;

5、   如果有匹配成功的catch则适应语句之中的代码进行异常的处理,如果始终没有匹配的catch,那么会将异常交由JVM执行默认处理;

6、   如果现在在程序之中存在有finally代码,那么在所有catch无法进行异常处理的时候,会判断是否有finally代码,如果有finally,则执行finally之中的程序后再交给JVM默认处理,所有的catch执行完毕之后也要判断是否存在finally;

7、   进入到finally代码之中有两种情况,一种是没有处理,则执行完finally代码之后,这之后的程序将不再执行了,而如果已经处理完异常,则继续执行finally之后的程序。

         通过以上的分析可以发现,所谓的异常的处理与catch匹配异常,那么就非常类似于方法的参数传递过程。唯一不同的是,此时的方法名称都统一使用了catch关键字表示,而所有的调用过程由try自动完成,那么既然是一个参数传递过程,就可以按照之前所学习过的对象自动向上转型的方式进行处理,所有的异常类都是Exception的子类,那么所有的异常都可以使用Exception处理。

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                            int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" + (x / y)) ;

                            System.out.println("******************") ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

提示:在使用多个catch进行处理的时候,捕获范围小的异常一定要放在捕获范围大的异常之前,否则将出现编译错误。

         如果在要求不严格的情况下,那么就可以使用Exception处理所有的异常信息,这也是大部分系统常用的做法。

1.4、throws关键字(重点)

         在类之中所有的操作都是以方法体现的,那么在方法的操作之中也是有可能出现异常的,如果说现在某些方法上出现异常之后希望被调用处进行处理的话,就使用throws进行声明。

范例:在方法定义上使用throws

class MyMath {

         public static int div(int x,int y) throws Exception {

                   return x / y ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println(MyMath.div(10,0)) ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

         因为日后肯定会使用到大量的Java类库进行项目的开发,那么这些类库可能是你不熟悉的,但是在类方法设计的时候会考虑到用户执行此处可能出现的问题,一般都会在方法上使用throws抛出异常,那么用户根据这些抛出就可以使用try..catch进行处理了。

         同时需要注意的是,既然方法上可以使用throws,那么在主方法上也可以使用throws,表示主方法也不处理异常。那么交给JVM进行处理。

class MyMath {

         public static int div(int x,int y) throws Exception {

                   return x / y ;

         }

}

public class TestDemo {

         public static void main(String args[])throws Exception {

                   System.out.println(MyMath.div(10,0)) ;

         }}

         一般这样的代码很少出现,因为如果在调用处一定要处理异常。

1.5、throw关键字

         如果在异常的处理之中,使用了throw,那么就表示人为抛出一个异常对象。而throw一般都在方法中使用。

范例:手工抛出异常

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            throw new Exception("自己抛着玩的") ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }       }

}

面试题:请解释throw和throws区别?

         · throw主要用于方法体之中,表示人为的抛出一个异常类的实例化对象;

         · throws在方法的声明处使用,表示此方法不处理异常,所有的异常交给被调用处进行处理。

1.6、第五个代码模型:异常处理结构(核心)

         那么到现在为止已经清楚了异常的基本处理形式,但是遗留的两个问题:finally无用、throw无用,那么为了更好的解释这两个操作的含义,给出一个异常处理的标准结构。

范例:现在要求定义一个div()方法(定义在MyMath类里面),这个方法开发要求如下:

         · 此方法之中所有出现的异常一定要交给被调用处进行处理;

         · 在进行除法计算开始首先要输出一行提示信息“1、除法计算开始,打开计算功能”;

         · 在除法计算进行完毕之后也要输出一行提示信息“2、除法计算结束,关闭计算功能”;

         在所有的开发之中,首先一定要完成的是基本功能,不考虑任何有可能出现错误的情况。

范例:基本要求

class MyMath {

         public static int div(int x,int y)throws Exception {    // 异常由被调用处处理

                   int result = 0 ;      // 保存除法计算结果

                  System.out.println("1、除法计算开始,打开计算功能。") ;

                   result = x / y ;      // 进行除法计算

                  System.out.println("2、除法计算结束,关闭计算功能。") ;

                   return result ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println("除法计算结果:"  + MyMath.div(10,2))  ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

1、除法计算开始,打开计算功能。

2、除法计算结束,关闭计算功能。

除法计算结果:5

         但是如果此时在除法计算过程之中出现了错误,则输出的信息如下。

1、除法计算开始,打开计算功能。

java.lang.ArithmeticException: / by zero

        at MyMath.div(TestDemo.java:5)

        at TestDemo.main(TestDemo.java:13)

         出错之后发现原本的设计是无法满足于当前要求的。

范例:标准结构

class MyMath {

         public static int div(int x,int y) throws Exception {        // 异常由被调用处处理

                   int result = 0 ;    // 保存除法计算结果

                   System.out.println("1、除法计算开始,打开计算功能。") ;

                   try {

                            result = x / y ;     // 进行除法计算

                   } catch (Exception e) {

                            throw e ;

                   } finally {

                            System.out.println("2、除法计算结束,关闭计算功能。") ;

                   }

                   return result ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println("除法计算结果:" + MyMath.div(10,0))  ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

         在本结构之中就出现了try、catch、finally、throw、throws的标准组合应用。日后可以把两条输出语句理解为资源的打开和资源的关闭。当然,以上的代码还可以更加的简化,直接使用try…finally操作。

class MyMath {

         public static int div(int x,int y) throws Exception {     // 异常由被调用处处理

                   int result = 0 ;      // 保存除法计算结果

                   System.out.println("1、除法计算开始,打开计算功能。") ;

                  try {

                            result = x / y ;     // 进行除法计算

                   } finally {

                            System.out.println("2、除法计算结束,关闭计算功能。") ;

                   }

                   return result ;

         }

}

         一般情况下,当捕获了异常之后往往需要简单的执行一些处理操作。

1.7、RuntimeException类

         那么下面首先来观察一段代码。

范例:将字符串变为int

public class TestDemo {

         public static void main(String args[]) {

                   int num = Integer.parseInt("123") ;

                   System.out.println(num * num) ;

         }

}

         但是现在来观察一下在Integer类之中parseInt()方法的定义。

public static int parseInt(String s) throws NumberFormatException

         发现在parseInt()方法定义的时候存在有throws关键字的抛出,按照之前所学,既然此处存在有throws,那么在调用时就应该使用try…catch进行处理。可是此时没有强迫性的要求使用异常处理,来观察一下NumberFormatException定义:

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.IllegalArgumentException

               |- java.lang.NumberFormatException 

         可以发现NumberFormatException不仅仅是Exception的子类,最重要的是,它还继承了RuntimeException,而在Java之中为了方便用户处理(并不是所有的异常都必须强制性处理),那么RuntimeException的子类往往可以由用户选择性进行处理,如果不需要也可以不处理。

面试题:请解释Exception和RuntimeException的区别?请列举出几个你常见的RuntimeException子类?

         · 用户可以处理的异常都要继承Exception类,而RuntimeException是Exception的子类;

         · Exception的异常要求用户强制性进行处理,而RuntimeException异常用户可以选择性进行处理,如果用户在编写代码过程之中没有处理,则出现异常后会由JVM进行默认处理。

         · 常见的RuntimeException子类(写出三、四个就可以):ArithmeticException、ClassCastException、NullPointerException、NumberFormatException、DOMException。

1.8、自定义异常类(理解)

         Java本身所提供的只是一个基础的异常处理操作支持,并且提供了一些比较常用的异常类型。但是在很多情况下有一些异常可能是不会提供的,例如:今天小金子吃饭吃多了,撑死的异常,这类异常Java是不可能提供的。所以此时如果要想面对于这类异常进行处理,则必须定义属于自己的异常类。

         那么要想定义属于自己的异常类,可以有两种选择:继承Exception或者是继承RuntimeException。

范例:定义自己的异常

class EatDieException extends Exception {       // 自定义异常

         public EatDieException(String msg) {

                   super(msg) ;        // 调用父类构造

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            for (int x = 1 ; x <= 30 ; x ++) {

                                     System.out.println("小金子吃饭,已经吃了:" + x + "吨的米饭。") ;

                                     if (x > 3) { // 吃3吨饭,不死也快了

                                               throw new EatDieException("小金子连续吃了超过三吨饭了,快完了。") ;

                                     }

                            }

                   } catch (Exception e) {

                                     System.out.println("No Zuo No Die .") ;

                                     e.printStackTrace() ;

                            }

         }

}

         在正常使用的情况下,很少会定义自己的异常类,但是如果在学习框架,或者是你日后设计框架的时候都有可能定义许多属于此框架的异常类。

1.9、断言:assert(了解)

         断言指的是在程序执行到某行语句的时候,一定是预期的结果,当然,断言有可能是错误的,也有可能是正确的。断言最早是在C++之中有所提供,后来到了JDK 1.4之后才增加了此关键字。

范例:观察断言

public class TestDemo {

         public static void main(String args[]) {

                   int x = 10 ;

                   // 现在假设中间经过了十行代码,都修改了x的内容

                  assert x == 100 : "断言错误信息:x的内容不是100,而是" + x ;

                   System.out.println("x = " + x) ;

         }

}

         默认情况下断言是不会启用的,如果要想让断言使用,则必须在执行的时候增加“-ea”参数“java -ea TestDemo”

Exception in thread "main" java.lang.AssertionError: 断言错误信息:x的内容不是100,而是10

        at TestDemo.main(TestDemo.java:5)

         此时断言出现了错误,所以执行时会出现一个“AssertionError”。




Java系列(十二)__Java异常处理

本次所讲解的内容没有人会说难,如果你还说难,只能表示一个结果,此处省略十个字。。。

1.1、认识异常(了解)

         异常指的是导致程序中断的一种指令流。那么下面先通过两个程序来比较程序出现异常与没有出现异常的区别。

范例:程序不出现异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   System.out.println("2、除法计算:" + (10 / 2)) ;

                   System.out.println("3、除法计算结束。") ;

         }

}

1、除法计算开始。

2、除法计算:5

3、除法计算结束。

         此时程序没有出现任何的异常,所以可以正常执行完毕。

范例:程序出现异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                  System.out.println("2、除法计算:" + (10 / 0)) ;  è 此处出错之后,此行和之后的所有行都不执行

                   System.out.println("3、除法计算结束。") ;

         }

}

1、除法计算开始。

Exception in thread "main" java.lang.ArithmeticException: / by zero

        at TestDemo.main(TestDemo.java:4)

         现在发现程序一旦出现了异常,将导致程序的中断执行,那么现在的问题是,即使出现了异常,我们也希望程序可以正常执行完毕。

1.2、处理异常(重点)

         如果在异常出现之后也希望程序可以正常的执行完毕,那么在Java里面就可以采用如下的代码结构来进行异常的处理操作。主要使用三个关键字:try、catch、finally。

try {

         // 有可能出现异常的代码

} [ catch (异常类型 对象) {

         异常处理代码 ;

} catch (异常类型 对象) {

         异常处理代码 ;

} ... ] [finally {

         不管是否有异常都要执行

}]

范例:处理异常

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try{

                            System.out.println("2、除法计算:" + (10 / 0)) ;

                            System.out.println("******************") ;  // 异常出现之后的代码都不执行

                  } catch (ArithmeticException e) {

                            System.out.println("出现异常:" + e) ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         此时程序出现异常之后,发现将直接跳转到catch之中进行处理,处理完成之后,程序正常结束。

范例:使用finally作为程序的出口

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            System.out.println("2、除法计算:" + (10 / 0)) ;

                            System.out.println("******************") ;

                   } catch (ArithmeticException e) {

                            System.out.println("出现异常:" + e) ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         对于finally暂时先有个了解,此部分代码是日后讲解的第五个代码模型的组成部分。

         但是在进行异常信息输出的时候,如果直接输出异常对象,那么只是告诉了用户是什么异常,但是异常的信息并不完整,那么如果希望异常的信息完整,可以调用异常类之中的“printStackTrace()”方法进行详细输出。

catch (ArithmeticException e) {

         e.printStackTrace() ;

}

         在之前给出的格式之中,发现可以在一个try语句之后跟上多个catch语句,那么下面就来观察此类操作。

范例:现在希望通过初始化参数,来输入两个计算的数字

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                           int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" +(x / y)) ;

                            System.out.println("******************") ;

                   }catch (ArithmeticException e) {

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         那么现在的程序就有可能出现下面的问题:

                   · 问题一:执行的时候没有输入参数(java TestDemo),ArrayIndexOutOfBoundsException,未处理;

                   · 问题二:输入的参数不是数字(java TestDemo a b),NumberFormatException,未处理;

                   · 问题三:输入数据的被除数是零(java TestDemo 10 0),ArithmeticException,已处理。

         那么现在发现程序之中,如果某些异常没有进行处理,那么程序依然会中断执行。所以就必须使用多个catch捕获。

范例:使用多catch操作

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                            int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" + (x / y)) ;

                            System.out.println("******************") ;

                   } catch (ArithmeticException e) {

                            System.out.println("〖ArithmeticException,算术异常。〗") ;

                            e.printStackTrace() ;

                   } catch (ArrayIndexOutOfBoundsException e) {

                            System.out.println("ArrayIndexOutOfBoundsException,数组越界异常。") ;

                            e.printStackTrace() ;

                   } catch (NumberFormatException e) {

                            System.out.println("NumberFormatException,数据转换异常。") ;

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

         此时已经可以成功的进行所有异常的处理。但是所有的异常都是经过了大量的分析之后才可以得出的处理方案,那么既然都已经分析完了,直接写几个if..else判断要比使用try…catch更加简单,那么异常处理有什么用呢?

1.3、异常的处理流程(重点)

         Java之中之所以会提供异常处理机制,主要的目的就是希望可以减少用户的if..else判断,所以来讲以上的处理方案只是一种严格的方案。那么如果说现在某些代码分析起来比较麻烦,希望可以通过一些简单的方式进行异常处理的话,那么之前所编写的多个catch就不这么好用了。那么下面就需要针对于异常做一个流程的说明。

         那么如果要想解决异常问题,首先来看一下关于异常的继承结构:

ArithmeticException:

NumberFormatException:

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.ArithmeticException

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.IllegalArgumentException

               |- java.lang.NumberFormatException  

         发现所有的异常都继承了Throwable类,而这个类指的就是抛出信息的操作类。在这个类之中发现有以下两个子类:

         (面试题:请解释Error和Exception的区别?

                   · Error:表示的是JVM系统出错,此时程序还没有执行,所以用户不能处理;

                   · Exception:表示的是所有程序运行过程之中出现的异常,用户可以进行处理。

         那么一般而言,由于Throwable表示的范围太大了,那么程序之中处理的往往不会是Throwable,而都是Exception。按照之前对象的向上转型自动完成的概念上来讲,所有的子类对象都可以使用父类接收,那么就表示所产生出来的所有异常应该都是Exception的子类,所有的异常对象都应该可以自动转为Exception。

面试题:请解释异常的处理流程


1、   当程序在运行过程之中产生了异常之后,那么会自动由JVM根据产生的异常类型,自动实例化一个与之相匹配的异常类对象(对象可以进行引用传递,可以包含很多的信息);

2、   此时JVM会判断在出现异常的代码之中是否存在有try语句进行异常的捕获;

3、   如果现在存在有try语句,则会由try捕获异常类的实例化对象,如果没有try,那么表示没有异常处理,则会将异常交给JVM采用默认的处理方式

4、   如果此时存在有try,那么会由try捕获异常,而后与try语句之后的每一个catch进行匹配,如果当前catch不匹配,则会交给后面的catch继续匹配;

5、   如果有匹配成功的catch则适应语句之中的代码进行异常的处理,如果始终没有匹配的catch,那么会将异常交由JVM执行默认处理;

6、   如果现在在程序之中存在有finally代码,那么在所有catch无法进行异常处理的时候,会判断是否有finally代码,如果有finally,则执行finally之中的程序后再交给JVM默认处理,所有的catch执行完毕之后也要判断是否存在finally;

7、   进入到finally代码之中有两种情况,一种是没有处理,则执行完finally代码之后,这之后的程序将不再执行了,而如果已经处理完异常,则继续执行finally之后的程序。

         通过以上的分析可以发现,所谓的异常的处理与catch匹配异常,那么就非常类似于方法的参数传递过程。唯一不同的是,此时的方法名称都统一使用了catch关键字表示,而所有的调用过程由try自动完成,那么既然是一个参数传递过程,就可以按照之前所学习过的对象自动向上转型的方式进行处理,所有的异常类都是Exception的子类,那么所有的异常都可以使用Exception处理。

public class TestDemo {

         public static void main(String args[]) {

                   System.out.println("1、除法计算开始。") ;

                   try {

                            // 接收参数数据,并且将其转为int型数据

                            int x = Integer.parseInt(args[0]) ;

                            int y = Integer.parseInt(args[1]) ;

                            System.out.println("2、除法计算:" + (x / y)) ;

                            System.out.println("******************") ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   } finally {

                            System.out.println("*** 不管是否有异常都要执行。") ;

                   }

                   System.out.println("3、除法计算结束。") ;

         }

}

提示:在使用多个catch进行处理的时候,捕获范围小的异常一定要放在捕获范围大的异常之前,否则将出现编译错误。

         如果在要求不严格的情况下,那么就可以使用Exception处理所有的异常信息,这也是大部分系统常用的做法。

1.4、throws关键字(重点)

         在类之中所有的操作都是以方法体现的,那么在方法的操作之中也是有可能出现异常的,如果说现在某些方法上出现异常之后希望被调用处进行处理的话,就使用throws进行声明。

范例:在方法定义上使用throws

class MyMath {

         public static int div(int x,int y) throws Exception {

                   return x / y ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println(MyMath.div(10,0)) ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

         因为日后肯定会使用到大量的Java类库进行项目的开发,那么这些类库可能是你不熟悉的,但是在类方法设计的时候会考虑到用户执行此处可能出现的问题,一般都会在方法上使用throws抛出异常,那么用户根据这些抛出就可以使用try..catch进行处理了。

         同时需要注意的是,既然方法上可以使用throws,那么在主方法上也可以使用throws,表示主方法也不处理异常。那么交给JVM进行处理。

class MyMath {

         public static int div(int x,int y) throws Exception {

                   return x / y ;

         }

}

public class TestDemo {

         public static void main(String args[])throws Exception {

                   System.out.println(MyMath.div(10,0)) ;

         }}

         一般这样的代码很少出现,因为如果在调用处一定要处理异常。

1.5、throw关键字

         如果在异常的处理之中,使用了throw,那么就表示人为抛出一个异常对象。而throw一般都在方法中使用。

范例:手工抛出异常

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            throw new Exception("自己抛着玩的") ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }       }

}

面试题:请解释throw和throws区别?

         · throw主要用于方法体之中,表示人为的抛出一个异常类的实例化对象;

         · throws在方法的声明处使用,表示此方法不处理异常,所有的异常交给被调用处进行处理。

1.6、第五个代码模型:异常处理结构(核心)

         那么到现在为止已经清楚了异常的基本处理形式,但是遗留的两个问题:finally无用、throw无用,那么为了更好的解释这两个操作的含义,给出一个异常处理的标准结构。

范例:现在要求定义一个div()方法(定义在MyMath类里面),这个方法开发要求如下:

         · 此方法之中所有出现的异常一定要交给被调用处进行处理;

         · 在进行除法计算开始首先要输出一行提示信息“1、除法计算开始,打开计算功能”;

         · 在除法计算进行完毕之后也要输出一行提示信息“2、除法计算结束,关闭计算功能”;

         在所有的开发之中,首先一定要完成的是基本功能,不考虑任何有可能出现错误的情况。

范例:基本要求

class MyMath {

         public static int div(int x,int y)throws Exception {    // 异常由被调用处处理

                   int result = 0 ;      // 保存除法计算结果

                  System.out.println("1、除法计算开始,打开计算功能。") ;

                   result = x / y ;      // 进行除法计算

                  System.out.println("2、除法计算结束,关闭计算功能。") ;

                   return result ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println("除法计算结果:"  + MyMath.div(10,2))  ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

1、除法计算开始,打开计算功能。

2、除法计算结束,关闭计算功能。

除法计算结果:5

         但是如果此时在除法计算过程之中出现了错误,则输出的信息如下。

1、除法计算开始,打开计算功能。

java.lang.ArithmeticException: / by zero

        at MyMath.div(TestDemo.java:5)

        at TestDemo.main(TestDemo.java:13)

         出错之后发现原本的设计是无法满足于当前要求的。

范例:标准结构

class MyMath {

         public static int div(int x,int y) throws Exception {        // 异常由被调用处处理

                   int result = 0 ;    // 保存除法计算结果

                   System.out.println("1、除法计算开始,打开计算功能。") ;

                   try {

                            result = x / y ;     // 进行除法计算

                   } catch (Exception e) {

                            throw e ;

                   } finally {

                            System.out.println("2、除法计算结束,关闭计算功能。") ;

                   }

                   return result ;

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            System.out.println("除法计算结果:" + MyMath.div(10,0))  ;

                   } catch (Exception e) {

                            e.printStackTrace() ;

                   }

         }

}

         在本结构之中就出现了try、catch、finally、throw、throws的标准组合应用。日后可以把两条输出语句理解为资源的打开和资源的关闭。当然,以上的代码还可以更加的简化,直接使用try…finally操作。

class MyMath {

         public static int div(int x,int y) throws Exception {     // 异常由被调用处处理

                   int result = 0 ;      // 保存除法计算结果

                   System.out.println("1、除法计算开始,打开计算功能。") ;

                  try {

                            result = x / y ;     // 进行除法计算

                   } finally {

                            System.out.println("2、除法计算结束,关闭计算功能。") ;

                   }

                   return result ;

         }

}

         一般情况下,当捕获了异常之后往往需要简单的执行一些处理操作。

1.7、RuntimeException类

         那么下面首先来观察一段代码。

范例:将字符串变为int

public class TestDemo {

         public static void main(String args[]) {

                   int num = Integer.parseInt("123") ;

                   System.out.println(num * num) ;

         }

}

         但是现在来观察一下在Integer类之中parseInt()方法的定义。

public static int parseInt(String s) throws NumberFormatException

         发现在parseInt()方法定义的时候存在有throws关键字的抛出,按照之前所学,既然此处存在有throws,那么在调用时就应该使用try…catch进行处理。可是此时没有强迫性的要求使用异常处理,来观察一下NumberFormatException定义:

java.lang.Object

   |- java.lang.Throwable

      |- java.lang.Exception

         |- java.lang.RuntimeException

            |- java.lang.IllegalArgumentException

               |- java.lang.NumberFormatException 

         可以发现NumberFormatException不仅仅是Exception的子类,最重要的是,它还继承了RuntimeException,而在Java之中为了方便用户处理(并不是所有的异常都必须强制性处理),那么RuntimeException的子类往往可以由用户选择性进行处理,如果不需要也可以不处理。

面试题:请解释Exception和RuntimeException的区别?请列举出几个你常见的RuntimeException子类?

         · 用户可以处理的异常都要继承Exception类,而RuntimeException是Exception的子类;

         · Exception的异常要求用户强制性进行处理,而RuntimeException异常用户可以选择性进行处理,如果用户在编写代码过程之中没有处理,则出现异常后会由JVM进行默认处理。

         · 常见的RuntimeException子类(写出三、四个就可以):ArithmeticException、ClassCastException、NullPointerException、NumberFormatException、DOMException。

1.8、自定义异常类(理解)

         Java本身所提供的只是一个基础的异常处理操作支持,并且提供了一些比较常用的异常类型。但是在很多情况下有一些异常可能是不会提供的,例如:今天小金子吃饭吃多了,撑死的异常,这类异常Java是不可能提供的。所以此时如果要想面对于这类异常进行处理,则必须定义属于自己的异常类。

         那么要想定义属于自己的异常类,可以有两种选择:继承Exception或者是继承RuntimeException。

范例:定义自己的异常

class EatDieException extends Exception {       // 自定义异常

         public EatDieException(String msg) {

                   super(msg) ;        // 调用父类构造

         }

}

public class TestDemo {

         public static void main(String args[]) {

                   try {

                            for (int x = 1 ; x <= 30 ; x ++) {

                                     System.out.println("小金子吃饭,已经吃了:" + x + "吨的米饭。") ;

                                     if (x > 3) { // 吃3吨饭,不死也快了

                                               throw new EatDieException("小金子连续吃了超过三吨饭了,快完了。") ;

                                     }

                            }

                   } catch (Exception e) {

                                     System.out.println("No Zuo No Die .") ;

                                     e.printStackTrace() ;

                            }

         }

}

         在正常使用的情况下,很少会定义自己的异常类,但是如果在学习框架,或者是你日后设计框架的时候都有可能定义许多属于此框架的异常类。

1.9、断言:assert(了解)

         断言指的是在程序执行到某行语句的时候,一定是预期的结果,当然,断言有可能是错误的,也有可能是正确的。断言最早是在C++之中有所提供,后来到了JDK 1.4之后才增加了此关键字。

范例:观察断言

public class TestDemo {

         public static void main(String args[]) {

                   int x = 10 ;

                   // 现在假设中间经过了十行代码,都修改了x的内容

                  assert x == 100 : "断言错误信息:x的内容不是100,而是" + x ;

                   System.out.println("x = " + x) ;

         }

}

         默认情况下断言是不会启用的,如果要想让断言使用,则必须在执行的时候增加“-ea”参数“java -ea TestDemo”

Exception in thread "main" java.lang.AssertionError: 断言错误信息:x的内容不是100,而是10

        at TestDemo.main(TestDemo.java:5)

         此时断言出现了错误,所以执行时会出现一个“AssertionError”。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值