java lang exception_Java基础-异常(Exception)处理

Java基础-异常(Exception)处理

作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.异常的概述

什么是异常?Java代码在运行时期发生的问题就是异常。在Java中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象,并抛出异常相关信息(如异常信息出现的位置,原因等)。

二.异常的继承体系

在Java中使用Exception类来描述异常。Exception类及其子类是Throwable的一种形式,它指出了合理应用程序想要捕获的异常条件。查看Java的API文档我们可以发现Exception有继承关系,它的父类是Throwable。Throwable是Java语言中所有错误或异常的超类。另外,在异常Exception类中,有一个子类要特殊说明一下,RuntimeException子类,RuntimeException及其它的子类只能在Java程序运行过程中出现。

我们再来观察Throwable类,能够发现与异常Exception平级的有一个Error,它是Throwable的子类,它用来表示Java程序中可能会产生的严重错误。解决办法只有一个,修改代码避免Error错误的产生。下面是一个Error异常的案例:

ccde4845886fc270d2fd8064194d86ab.png

综上所述,异常继承体系可以大致做以下简要分类,此处并未列出全部的异常,请以Java的API文档为标准,下图只是为了方便记忆:

3087db30b4dbfb19caee1d4b74ff74b6.png

三.异常对象的产生原因和处理方式

6b67720bf72e828c4f6ea557881036c0.png

我们看见上面的代码是有异常抛出的,那么异常究竟是怎么抛出的呢?其实他大致分为以下几个步骤:

1>.JVM检测到异常

通过上面的学习,我们知道异常的祖宗其实就是Throwable类,在这个类下面很多个子类已经提前定义好了。在代码运行的时候,JVM是完全有能力检测到出现的异常信息(比如:ArrayIndexOutOfBoundsException)。

2>.JVM创建异常对象

当JVM虚拟机检测到异常后,首先会创建异常对象(比如:new  java.lang.ArrayIndexOutOfBoundsException: 5)。

3>.将异常抛给方的调用者

当创建好异常后,首先JVM虚拟机会检测程序手否对这种类型的异常有相应的处理方式,如果有,则按照业务逻辑执行,如果没有,就会将异常的对象进行抛出,最终会抛给方法的调用者。

4>.调用者继续抛出异常

从上面的代码中可以看到,getAway方法的调用者是main函数,因此会把异常抛给main方法,JVM虚拟机又会在main方法查找是否有异常处理的方式,如果没有对数组越界异常进行处理就将异常对象(java.lang.ArrayIndexOutOfBoundsException: 5)继续向上抛出,也就是main方法的调用者。而main方法运行在栈内存中,实际上是抛给了JVM虚拟机啦。

5>.JVM虚拟机收到异常后的事情

其实JVM虚拟机(最终异常的处理者)收到异常后,做了两件事情:

a>.将异常信息的内容输出,让程序员进行排错;

b>.杀死抛出异常的进程(也就是结束main方法);

四.方法内部抛出对象关键字(throw)

在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首选需要先对参数数据进行合法判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。在Java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 public static voidmain(String[] args){9 int[] arr = null;10 //int[] arr1 = {};

11 int i =getArray(arr);12 System.out.println(i);13 }14

15 //对数组的最后索引*2,返回

16 public static int getArray(int[] arr){17 //对方法参数进行合法性的判断,进行判断是不是null

18 if(arr == null){19 //通过关键字throw抛出异常的形式,告诉调用者。

20 throw new RuntimeException("传递的数组不存在");21 }22

23

24 //对数组进行判断,判断数组中是否储存在元素。

25 if(arr.length == 0){26 //以抛出异常的形式,告诉调用者,数组中没有元素

27 throw new RuntimeException("传递的是空数组");28 }else{29 int i = arr[arr.length-1];30 return i*2;31 }32 }33 }34

35

36 /*

37 以上代码执行结果如下:38 Exception in thread "main" java.lang.RuntimeException: 传递的数组不存在39 at ExceptionDemo.getArray(ExceptionDemo.java:20)40 at ExceptionDemo.main(ExceptionDemo.java:11)41 */

42

43

44

五.异常方法声明关键字(throws)

throws用于在方法的声明上,标明此方法可能出现异常的类型,让调用者自己处理。换句话说,调用了一个抛出异常的方法,调用者就必须处理,若不处理,就会编译失败。

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法将异常抛给了JVM虚拟机。

9 public static void main(String[] args) throwsException{10 //int[] arr1 = null;

11 int[] arr2 ={};12 int i =getArray(arr2);13 System.out.println(i);14 }15

16 //对数组的最后索引*2,通过throws关键字声明抛出的异常,调用者必须处理,否则编译失败!

17 public static int getArray(int[] arr) throwsException{18 //对方法参数进行合法性的判断,进行判断是不是null

19 if(arr == null){20 //通过关键字throw抛出异常的形式,告诉调用者。

21 throw new Exception("传递的数组不存在");22 }23

24

25 //对数组进行判断,判断数组中是否储存在元素。

26 if(arr.length == 0){27 //以抛出异常的形式,告诉调用者,数组中没有元素

28 throw new Exception("传递的是空数组");29 }else{30 int i = arr[arr.length-1];31 return i*2;32 }33 }34 }35

36

37 /*

38 以上代码执行结果如下:39 Exception in thread "main" java.lang.Exception: 传递的是空数组40 at ExceptionDemo.getArray(ExceptionDemo.java:28)41 at ExceptionDemo.main(ExceptionDemo.java:12)42 */

43

44

45

六.Java中的异常处理方式

1>.异常处理格式

1 try{2 被检测的代码;3 可能出现异常的代码;4 }catch(异常类名变量){5 异常的处理方式;6 循环,判断,调用方法,变量7 }finally{8 必须要执行的代码;9 }

2>.try...异常处理

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法进行处理异常

9 public static voidmain(String[] args){10 int[] arr = null;11 try{12 int i =getArray(arr);13 System.out.println(i);14 }catch(NullPointerException e) {15 System.out.println(e);16 }17 System.out.println("Game Over!");18 }19

20 //创建异常对象并抛出

21 public static int getArray(int[] arr) throwsNullPointerException{22 //对方法参数进行合法性的判断,进行判断是不是null

23 if(arr == null){24 //手动抛出异常,抛出空指针异常

25 throw new NullPointerException("传递的数组不存在");26 }27

28 //对数组的索引进行判断

29 if(arr.length < 3){30 //手动抛出异常,抛出数组的索引越界异常

31 throw new ArrayIndexOutOfBoundsException("数组没有下标为3的索引");32 }33 return arr[3]+1;34 }35 }36

37

38

39

40

41

42 /*

43 以上代码执行结果如下:44 java.lang.NullPointerException: 传递的数组不存在45 Game Over!46

47

48 */

49

50

51

ExceptionDemo.java 文件内容

a7ee69f61700b1929e8e3201ac0fb299.png

3>.异常多catch处理

平级异常,抛出的异常类之间,没有继承关系。上下级关系的异常,越高级的父类越应该写在下面。

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法进行处理异常

9 public static voidmain(String[] args){10 int[] arr = new int[0];11 try{12 int i =getArray(arr);13 System.out.println(i);14 }catch(NullPointerException e) {15 System.out.println(e);16 }catch(ArrayIndexOutOfBoundsException e) {17 System.out.println(e);18 }catch(Exception e){ //Exception应该放在最后一个catch,因为它包含上面2种异常。

19 System.out.println(e);20 }21 System.out.println("Game Over!");22 }23

24 //可以抛出多个异常

25 public static int getArray(int[] arr) throwsNullPointerException,ArrayIndexOutOfBoundsException{26 //对方法参数进行合法性的判断,进行判断是不是null

27 if(arr == null){28 //手动抛出异常,抛出空指针异常

29 throw new NullPointerException("传递的数组不存在");30 }31

32 //对数组的索引进行判断

33 if(arr.length < 3){34 //手动抛出异常,抛出数组的索引越界异常

35 throw new ArrayIndexOutOfBoundsException("数组没有下标为3的索引");36 }37 return arr[3]+1;38 }39 }40

41

42

43

44 /*

45 以上代码执行结果如下:46 java.lang.ArrayIndexOutOfBoundsException: 数组没有下标为3的索引47 Game Over!48 */

4>.finnal代码块

finally中的代码块无论程序是否有异常,程序都必须执行里面的代码(除非你在来到finally之前就用System.exit(0)退出程序啦!)。它一般用来释放IO资源,比如关闭文件或者关闭数据库的链接等等。

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法进行处理异常

9 public static voidmain(String[] args){10 int[] arr = new int[0];11 try{12 function(100);13 }catch(Exception e){14 System.out.println(e);15 }finally{16 System.out.println("必须要执行的代码!");17 }18 System.out.println("Game Over!");19 }20

21 //创建异常对象并抛出

22 public static void function(int a) throwsException{23 if(a == 0) {24 throw newException();25 }else{26 System.out.println(a);27 }28 }29 }30

31

32

33

34

35

36 /*

37 以上代码执行结果如下:38 10039 必须要执行的代码!40 Game Over!41 */

5>.运行时期异常的特点

异常分为编译异常和运行时异常。

a>.编译异常

调用了抛出异常的方法(抛出编译异常需要在方法上用关键字throws声明异常),不处理的话就会编译不通过。处理方式有两种,第一种就是用try语句进行处理,或者是用throws语句丢给调用者去处理。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法进行处理异常

9 public static voidmain(String[] args){10 int[] arr = new int[0];11 try{12 function(100);13 }catch(Exception e){14 System.out.println(e);15 }finally{16 System.out.println("必须要执行的代码!");17 }18 System.out.println("Game Over!");19 }20

21 //抛出编译异常需要在方法上用关键字throws声明异常

22 public static void function(int a) throwsException{23 //创建编译异常

24 throw newException();25 }26 }27

28

29

30

31 /*

32 以上代码执行结果如下:33 java.lang.Exception34 必须要执行的代码!35 Game Over!36

37 */

编译异常(Exception)案例展示

b>.运行时期异常

抛出的异常是RuntimeException类,或者是他的子类。方法内部抛出的异常是运行异常,在方法声明上,不需要throws语句。不仅如此,运行时异常我们也不需要去用try语句或者throws语句去处理。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7 public classExceptionDemo{8 //main方法进行处理异常

9 public static voidmain(String[] args){10 //调用者,不需要处理异常

11 function(100);12 }13 //运行时异常可以不用在方法上用关键字throws声明。

14 public static void function(inta){15 //创建运行时异常

16 throw newRuntimeException();17 }18 }

运行时异常(RuntimeException)案例展示

c>.运行异常的设计原因

运行异常,在编译的时候不能察觉出来,如果发生了运行异常,程序人员停止程序修改源代码。运行异常一旦发生,后面的代码没有执行的意义。比如我们看下面一段代码,估计身为老司机的你一眼就看出问题了,但是在编译的时候就不死活不报错,一旦你运行就会崩溃。

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 public classExceptionDemo{9 public static voidmain(String[] args){10 int[] arr = {1,2,3};11 function(arr);12 }13

14 public static void function(int[] arr){15 /*此处我们对数组的第六个元素进行操作,但是如果传入的数组长度不到6,16 *则继续向下执行代码就没有任何意义,程序员应该修改以下的代码逻辑性!17 */

18 if(arr[5] > 100) {19 arr[5] = arr[5]/10;20 }else{21 arr[5] = arr[5]/3;22 }23 }24 }

d>.运行异常的案例

定义一个方法,计算一个圆形面积。传递参数为负数时可以完成计算,但是违反了真实情况,因此我们可以将传入的数据进行判断,如果不符合现实情况就让程序崩溃掉,让调用者传入合法的数据信息,我们举一个简单的案例(求圆形的面积,你可以补充求周长来练习):

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 public classExceptionDemo{9 public static voidmain(String[] args){10 //传入一个负数去求面积,会导致程序崩溃

11 double d = getArea(-1);12 System.out.printf("圆形的面积是:%f\n",d);13 }14

15 //定义方法,计算圆形的面积

16 public static double getArea(doubler){17 //当传入的半径是非正数时,就让程序崩溃掉!

18 if(r <= 0) {19 throw new RuntimeException("圆形不存在");20 }21 return r*r*Math.PI;22

23 }24 }25

26

27

28 /*

29 以上代码执行结果如下:30 Exception in thread "main" java.lang.RuntimeException: 圆形不存在31 at ExceptionDemo.getArea(ExceptionDemo.java:19)32 at ExceptionDemo.main(ExceptionDemo.java:11)33

34 */

6>.方法重写时候异常的处理

继承后,在子类重写父类方法的时候,异常处理结论:

a>.父类的方法如果抛出异常,子类重写后可以不抛出异常,也可以不抛出异常,但是,如果子类要抛,抛出的异常不能大于父类的异常(都指的是继承关系);

b>.父类的方法没有异常抛出,子类重写后也不能抛出异常;

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 public classExceptionDemo{9 public static voidmain(String[] args){10

11 }12 }13

14 classFather{15 public void function()throwsException{16

17 }18 }19

20 class Son extendsFather{21 //子类可以抛出异常也可以不抛出异常Exception

22 public voidfunction(){23

24 }25 }

父类抛出异常,子类可以不抛出异常

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 public classExceptionDemo{9 public static voidmain(String[] args){10

11 }12 }13

14 classFather{15 public voidfunction(){16

17 }18 }19

20 class Son extendsFather{21 //子类可以抛出异常也可以不抛出异常Exception

22 public voidfunction(){23

24 }25 }

父类不抛出异常,子类就不能抛出异常

七.自定义异常

1>.Throwable类常用的方法

a>.String getMessage()    :对异常信息的详细描述。

b>.String toString()    :对异常信息的简短描述。

c>.void printStackTrace()  :将异常信息追踪到标准的错误流,也是JVM虚拟机默认调用的方式,因为它的异常信息最详细。

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 public classExceptionDemo{9 public static voidmain(String[] args){10 try{11 function();12 }catch(Exception e) {13 System.out.println(e.getMessage());14 System.out.println(e.toString());15 e.printStackTrace(); //JVM默认调用的就是这个方法,异常信息最全。

16 }17

18 }19

20

21 public static void function() throwsException{22 throw new Exception("异常啦!");23 }24

25 }26

27

28

29 /*

30 以上代码执行结果如下:31 异常啦!32 java.lang.Exception: 异常啦!33 java.lang.Exception: 异常啦!34 at ExceptionDemo.function(ExceptionDemo.java:22)35 at ExceptionDemo.main(ExceptionDemo.java:11)36 */

2>.自定义异常

1 /*

2 @author :yinzhengjie3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/

4 EMAIL:y1053419035@qq.com5 */

6

7

8 //自定义异常类

9 class MyException extendsRuntimeException{10

11 MyException(String message){12 super(message);13 }14 }15

16 public classExceptionDemo{17 public static voidmain(String[] args){18 try{19 test();20 }catch(MyException e){21 System.out.println(e.getMessage());22 //....

23 }24 }25

26 public static void test() throwsMyException {27 throw new MyException("发生自定义异常!");28 }29 }30

31

32

33 /*

34 以上代码执行结果如下:35 发生自定义异常!36 */

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值