java异常类层次结构图-java 枚举类 异常参数
1 概述
Java代码中的异常处理是一个非常重要的部分。 从代码中可以看出其使用已经与业务逻辑紧密结合。 部分业务逻辑还是由异常来完成,更多的时候是处理异常。 可以改善逻辑,避免可能的错误,避免小错误造成的大停顿。
在一般的项目中,运行时异常会被定制以满足项目的需要。 可以捕获或不捕获此类异常。 它们不会导致整个系统挂掉,但在很多情况下,没有被捕获和处理就会导致业务出错。
这里我们模拟几种情况,指出什么时候使用异常捕获。
2、情况分析
先看没有任何处理的代码
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7
8}9
10 公共静态 voidinvoke(){11 System.out.println("---11---");12 int i = 1/0;13 System.out.println("---12---") ;14 }15 }
其执行结果如下:
---1---
---11---线程“main”中的异常java.lang.ArithmeticException:/为零
在 com.donghao.test1.ExceptionTests01.invoke(ExceptionTests01.java:14)
在 com.donghao.test1.ExceptionTests01.main(ExceptionTests01.java:7)
分析:main方法调用invoke方法,执行到第12行出错,导致算法异常。 此时,由于没有异常处理方法,结果是程序执行到这里就直接中断了,执行结果中输出的异常堆栈信息是Java内部默认的异常处理机制的结果。
修改一:我们在invoke方法内部添加异常捕获机制,代码如下:
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7
8}9
10 public static voidinvoke(){11 try{12 System.out.println("---11---");13 int i = 1/0;14 }catch(Exception e){15 System.out.println ("---12---");16 }17 System.out.println("---13---");18 }19 }
结果:
---1---
---11---
---12---
---13---
---2---
结果分析:我们在invoke方法的执行代码周围添加异常捕获代码来捕获Exception,它是所有异常的基类,当然这里也包括算法异常,那么这个捕获机制会捕获1/产生的异常0 捕获到这个异常后,会跳转到catch语句块执行这个异常的处理语句。 执行完成后,会继续执行try...catch语句块之后的代码。 这样做的好处是显而易见的。 一个小错误不会妨碍整个代码的继续执行。 当然,如果是比较严重的问题,我们确实需要暂停执行,所以不能使用这种情况。 只是用前面的代码,所以异常处理机制的执行时机完全根据项目的业务情况而定,非常灵活,不是一成不变的。 根据实际业务场景合理使用。
改造2:我们在main方法中也加入了异常捕获
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 try{5 System.out.println("---1---");6 invoke();7 }catch(Exception e){8 System.out. println("---2---");9 }10 System.out.println("---3---");11 }12
13 public static voidinvoke(){14 try{15 System.out.println("---11---");16 int i = 1/0;17 }catch(Exception e){18 System.out.println ("---12---");19 }20 System.out.println("---13---");21 }22 }
其执行结果如下:
---1---
---11---
---12---
---13---
---3---
结果和之前几乎一模一样。 不同的是2没有输出。 一是我把2的输出位置改了,加上了3的输出,现在3相当于之前2的位置。 2之所以没有输出是因为Any exception只能被捕获一次。 一旦被捕获并处理,以后就不会再被捕获。 即使我在main方法中把异常类型改成算法异常,也不会被捕获java异常类层次结构图,只会捕获离它最近的异常。 包含异常的异常捕获,这里的两次异常捕获其实是嵌套的异常捕获,两者捕获的异常还是一致的。 一般情况下,我们不会使用这个,因为它没有意义。 但不代表它完全不会出现。 可能invoke里面的代码比较长,会出现多个异常。 我们可以在main方法中捕获,invoke中的异常捕获只是针对单个异常,说明该异常的发生不会影响invoke方法后面代码的执行。 一旦没有异常捕获的代码发生异常,就会中断后面所有代码的执行(在同一个代码块中)。 这个异常会被main方法中的异常捕获机制捕获并执行。 处理,使得main方法中调用invoke之后的代码仍然可以执行,不会因为调用导致的异常而中断。
但是如果我们把invoke方法中的异常捕获改成如下:
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 try{5 System.out.println("---1---");6 invoke();7 }catch(Exception e){8 System.out. println("---2---");9 }10 System.out.println("---3---");11 }12
13 public static voidinvoke(){14 try{15 System.out.println("---11---");16 int i = 1/0;17 }catch(NullPointerException e){18 System.out.println ("---12---");19 }20 System.out.println("---13---");21 }22 }
执行结果发生了变化:
---1---
---11---
---2---
---3---
为什么? 正是因为我们更改了invoke方法中捕获的异常类型。 之前是异常基类型Exception,现在改为具体的空指针异常。 那么这个异常捕获只能捕获到空指针异常。 它对此处发生的算法异常没有影响。 会视而不见(由于错误的异常类型,那么这个异常捕获就相当于没有加法,可以想象成没有异常捕获的情况),这样会导致invoke方法中的所有代码在1/0之后发生的异常不会被执行。 ,但是我们在main方法中新增的异常捕获可以捕获这个算法异常,所以12和13不会输出,而是在异常发生后直接跳转到main方法捕获异常,并执行catch语句块处理语句输出 2,然后是 3。
看一个特例:
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7 }8
9 public static voidinvoke(){10 for(int i = -2;i < 3;i++){11 System.out.println("---11---");12 System.out.println("12 /"+i+"="+12/i";13 System.out.println("---12---");14 }15 System.out.println("---13---") ;16 }17 }
invoke 方法是一个循环输出。 当第 12 行发生异常时,循环被中断。 默认异常处理机制打印异常堆栈:
---1---
---11---
12/-2=-6
---12---
---11---
12/-1=-12
---12---
---11---线程“main”中的异常java.lang.ArithmeticException:/为零
在 com.donghao.test1.ExceptionTests01.invoke(ExceptionTests01.java:14)
在 com.donghao.test1.ExceptionTests01.main(ExceptionTests01.java:7)
修改一:在invoke方法的for循环外添加try...catch:
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7 }8
9 public static voidinvoke(){10 try{11 for(int i = -2;i < 3;i++){12 System.out.println("---11---");13 System.out.println ("12/"+i+"="+12/i);14 System.out.println("---12---");15 }16 System.out.println("---13-- -");17 }catch(异常 e){18 System.out.println("---14---");19 }20 System.out.println("---15---"); 21}22}
结果:
---1---
---11---
12/-2=-6
---12---
---11---
12/-1=-12
---12---
---11---
---14---
---15---
---2---
查看结果,发现循环还是中断了。 当i=0时,第13行产生异常,然后循环中断,然后异常会被for循环外的异常捕获。 这种场景在实际项目中也会出现。 但这种情况很少见。 具体场景是为循环捕获异常。 一旦循环中的某个循环出现异常,整个循环就会终止,异常就会被处理。
改造 2:在循环体中添加一个 try...catch 块
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7 }8
9 public static voidinvoke(){10 for(int i = -2;i < 3;i++){11 try{12 System.out.println("---11---");13 System.out.println ("12/"+i+"="+12/i);14 System.out.println("---12---");15 }catch(Exception e){16 System.out.println(" ---13---");17 }18 System.out.println("---14---");19 }20 System.out.println("---15---"); 21}22}
结果:
---1---
---11---
12/-2=-6
---12---
---14---
---11---
12/-1=-12
---12---
---14---
---11---
---13---
---14---
---11---
12/1=12
---12---
---14---
---11---
12/2=6
---12---
---14---
---15---
---2---
这种情况比较常见。 我们将异常捕获内置到for循环内部,只捕获循环体的异常。 这样当某个循环体执行过程中出现异常时,可以私下处理,不影响整个循环的继续进行。 实施。 在循环中,还可以结合continue和break关键字进行更复杂的关系控制,以满足特定的业务需求。
这里我展示一个情况,也是我刚才做的一个业务场景:
1 个公共类异常测试 01 {2
3 public static voidmain(String[] args) {4 System.out.println("---1---");5 invoke();6 System.out.println("---2---" );7 }8
9 public static voidinvoke(){10 for(int i = -2;i < 3;i++){11 try{12 System.out.println("---11---");13 System.out.println ("12/"+i+"="+12/i);14 System.out.println("---12---");15 }catch(Exception e){16 System.out.println(" ---13---");17 继续;18 }19 System.out.println("---14---");20 }21 System.out.println("---15--- ");22 }23 }
你没看错,加一个continue; 控制信息的显示,当异常发生时,执行catch块代码,输出13后,不再执行输出14的操作,直接开始新的循环。
有必要做一个总结:
1- 异常的捕获是有方向的和类型特定的,异常会被离异常发生点最近的遏制点或捕获该类型异常的捕获点捕获。 这样我们在做嵌套异常捕获和多重异常捕获的时候,一定要注意把小规模的异常类型放在靠近try块的地方,避免大类型劫持异常,导致你设置的异常类型失败生效。
2- 我们可以通过用 try...catch 包装一段代码,将这段代码与方法体隔离开来,并将其影响降到最低。 即使发生异常,也不会影响后续代码的执行。
3-throw关键字与catch块配合使用,表示捕获到的异常会再次抛出,这里不处理,所以必须在方法调用时再次捕获,才能继续被抛出,但是直到最后一个方法,它必须被处理(显式抛出的异常必须被捕获和处理,无论你抛出多少次)。
三、项目异常处理
异常转换
我们会在项目中自定义异常。 这些例外通常有明确的目的。 我们甚至可以在项目的每个级别定义不同的异常。 这时候就会涉及到异常转换。 其实转换很简单,只要Catch异常java异常类层次结构图,在catch块中捕获一行,重新抛出(throw)一个新的异常,将之前的异常信息e作为新异常的参数即可。
1 try{2 int i = 1/0;3 }catch(Exception e){4 throw newRuntimeException(e);5 }
如上例,第2行会抛出一个异常,该异常会被catch块捕获,然后在内部进行消化,重新抛出一个RuntimeException,并将原来的异常信息作为新异常的异常信息(即保持原来的异常消息)。