java学习--抛出异常
1.5k6 分钟
原文链接:https://www.cnblogs.com/Time25/p/20025633.html
异常的传播
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } }
static void process1() { process2(); }
static void process2() { Integer.parseInt(null); } } 当某个方法抛出了异常时,如果当前方法没有捕获异常,异常就会被抛到上层调用方法,直到遇到某个try ... catch被捕获为止:
main()调用process1(); process1()调用process2(); process2()调用Integer.parseInt(String); Integer.parseInt(String)调用Integer.parseInt(String, int)。
也叫异常的传播
查看Integer.java源码可知,抛出异常的方法代码如下:
public static int parseInt(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } ... }
|
异常的抛出
1 2
| 创建某个Exception的实例; 用throw语句抛出。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void process2(String s) { if (s==null) { NullPointerException e = new NullPointerException(); throw e; } }
//也就是 void process2(String s) { if (s==null) { throw new NullPointerException(); } }
|
异常的类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void process1(String s) { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(); } }
void process2(String s) { if (s==null) { throw new NullPointerException(); } }
|
但是异常类型转换有一个问题就是,先看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } }
static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(); } }
static void process2() { throw new NullPointerException(); } }
|
为了能追踪到完整的异常栈,在构造异常的时候,把原始的Exception实例传进去,新的Exception就可以持有原始Exception信息。对上述代码改进如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } }
static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(e); } }
static void process2() { throw new NullPointerException(); } }
|
捕获到异常并再次抛出时,一定要留住原始异常,否则很难定位第一案发现场!
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Main { public static void main(String[] args) { try { Integer.parseInt("abc"); } catch (Exception e) { System.out.println("catched"); throw new RuntimeException(e); } finally { System.out.println("finally"); } } }
|
小疑问:
如果在finally里面抛出的异常时前面catch可以接受的异常,那么是不是会一直循环呢?
答案是不会的,而且这样非常蠢,会让程序直接崩掉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public static void main(String[] args) { try { System.out.println("1. 执行 try"); throw new IOException(); } catch (IOException e) { System.out.println("2. 捕获到了 try 里的 IOException"); } finally { System.out.println("3. 执行 finally"); throw new IOException("Finally 里的异常"); } }
程序的实际运行路径 执行 try:抛出了 IOException。 执行 catch:匹配成功,打印 "捕获到了..."。 执行 finally:打印 "执行 finally"。 finally 抛出异常:重点来了! 这个异常发生在 finally 块里。 当前的 catch 块已经执行过了,或者说它已经完成了它的使命。 Java 不会“回头”再去检查刚才那个 catch 能不能抓到这个新异常。 结果:这个异常会直接冲破整个 try-catch-finally 结构,抛给给调用它的上层(在上面的例子中,就是抛给 JVM,导致程序崩溃并打印堆栈信息)。
如果一定要在finally里面先抛出一个异常,那么就是再套一层try catch try { try { } catch (IOException e) { } finally { throw new IOException(); } } catch (IOException e) { System.out.println("这里才能抓到 finally 里的异常"); }
|
异常屏蔽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Main { public static void main(String[] args) { try { Integer.parseInt("abc"); } catch (Exception e) { System.out.println("catched"); throw new RuntimeException(e); } finally { System.out.println("finally"); throw new IllegalArgumentException(); } } }
|
完整异常显示
//在极少数的情况下,我们需要获知所有的异常。如何保存所有的异常信息?方法是先用origin变量保存原始异常,然后调用Throwable.addSuppressed(),把原始异常添加进来,最后在finally抛出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class Main { public static void main(String[] args) throws Exception { Exception origin = null; try { System.out.println(Integer.parseInt("abc")); } catch (Exception e) { origin = e; throw e; } finally { Exception e = new IllegalArgumentException(); if (origin != null) { e.addSuppressed(origin); } throw e; } } }
public class Main { public static void main(String[] args) { try { runDangerousCode(); } catch (Exception e) { System.out.println("捕获到了主异常: " + e.getClass().getName());
Throwable[] suppressed = e.getSuppressed(); for (Throwable s : suppressed) { System.out.println("发现被屏蔽的附件异常: " + s); } } }
public static void runDangerousCode() throws Exception { Exception origin = null; try { Integer.parseInt("abc"); } catch (Exception e) { origin = e; throw e; } finally { Exception e = new IllegalArgumentException(); if (origin != null) { e.addSuppressed(origin); } throw e; } } }
|
// TRAINING LOG · 第 65 / 76 篇训练记录 · 成文于 2026.05.12 · 夜间 19:11