Java异常
Java笔记
一、简介
-
一个健壮的程序必须能够处理各种异常。
-
我们应该如何处理异常?两种方式:
- 返回约定错误码,例如200表示成功。
- 在语言层面提供异常处理机制。
-
必要性说明:
- 异常需要被分门别类区处理的,不推荐直接使用 Exception 类捕获所有异常,这不是一个好的习惯。
- 发生异常时,程序会被从异常发生处开始中断。
- 异常与错误,并不一样。Throwable 中有两个体系:Error和Exception,虽然两者都会被抛出,但是 Error 表示严重的错误,程序一般对此无能为力。
- 在Java体系中存在一些必须要捕获的异常。如果这些异常没有对应的捕获语句,那么编译器会编译失败。
- 如果在方法头中标记了可能抛出的异常,那么我们在编写
try()
语句的时候就可以不用编写catch语句。【注意是 try() 而不是 try 】 - 所有未捕获的异常,最终都会在main()中出现,我们必须要在main方法中设法捕获所有异常
-
Java异常库
-
异常处理顺序原则:从小到大,最后 Exception 包揽全部。
try { // } catch (IOException e) { // io error: } catch (Exception e) { // other error: } -
概念:异常栈
- 当发生异常时,会按照顺序依次抛出异常,所以Java程序中存在异常栈。
printStackTrace()
方法负责打印异常栈,每层调用都会给出对应的源代码行号,这对于调试错误非常有用。
java.lang.NumberFormatException: null at java.base/java.lang.Integer.parseInt(Integer.java:614) at java.base/java.lang.Integer.parseInt(Integer.java:770) at Main.process2(Main.java:16) at Main.process1(Main.java:12) at Main.main(Main.java:5) 上述信息表示:numberFormatException是在Java.lang.integer.parseInt方法中抛出的,从下往上看,调用层依次是
-
关键性的Cause by
- Cause by 通常是具体的抛出异常原因,可口语化表示。
- 自定义 Cause by:initCause 初始化异常对象。
try { int a = 1 / 0; } catch (Exception ex) { throw new Exception().initCause(new Throwable("自定义")); } -
4种异常类【输出方法】
- 原生
int a = 1 / 0; Exception in thread "main" java.lang.ArithmeticException: / by zero at com.thinkstu.csdn.controller.test.main(test.java:9) - printStackTrace():同原生
try { int a = 1 / 0; } catch (Exception ex) {ex.printStackTrace();} Exception in thread "main" java.lang.ArithmeticException: / by zero at com.thinkstu.csdn.controller.test.main(test.java:9) - getMessage():简短
try { int a = 1 / 0; } catch (Exception ex) { System.out.println(ex.getMessage()); } / by zero - toString():折中
try { int a = 1 / 0; } catch (Exception ex) { System.out.println(ex.toString()); } java.lang.ArithmeticException: / by zero -
关于finally语句的几个特点:
- finally语句不是必须的。
- finally语句总是最后执行。
- 就算不发生异常,finally语句也会被执行。
-
异常参数混合使用规则:
|
号分割。public static void main(String[] args) { try { process1(); } catch (IOException | NumberFormatException e) { } } -
概念:异常转换、异常屏蔽
-
如果在 catch 里把异常捕获,又把异常抛出去(可以这样做),那么最终异常还是会被抛出该方法,俗称**【异常转换】**。
-
注意,在异常转换时需要把原始的异常信息补充进去,以免丢失原始的异常信息、难以定位第一案发现场。另外,再次抛出异常并不会影响原 finally 语句的执行,此时程序的执行顺序为 try → catch → finally → throw 。
-
但是,如果是在 finally 语句中抛出了异常,那么结果就是 finally 中的异常会被正确抛出,而 catch 里的异常则不会被抛出,这种情况需要格外注意,俗称**【异常屏蔽】**。
try { process(); } catch (NullPointerException oldMsg) { // 保留原始的异常信息 throw new IllegalArgumentException( oldMsg ); } try { process(); } catch (Exception e) { throw new RuntimeException(e); } finally { // 屏蔽了 catch 中新抛出的异常 throw new IllegalArgumentException(); } -
二、空指针异常
空指针异常是 Java 异常体系中重要章节
-
空指针异常(NPE):Null Point Exception。
-
产生原因:如果一个对象为 null ,那么调用该对象方法或字段就会产生空指针异常 NullPointException ,这个异常通常是由JVM抛出的。
-
必要性说明:
- 空指针是一种代码逻辑错误。
- 指针概念源于C语言,Java 中并无指针。我们所说的 Java 空指针异常实际上指的是 Java 引用异常(Null Reference),不过两者的差别不大。
- 好的编程习惯可以在一定程度上避免空指针的发生。例如在定义 String 变量时,使用空字符串
""
而不是默认的 null 可以避免 NullPointException 的发生。
// 好的编程习惯范例 public String[] test1(String file) { private String name = ""; if (getFileSize(file) == 0) { return new String[0]; } }
三、自定义异常
尽量使用 JDK 提供的异常类型(存在即使用),而不是自定义异常。
- 简介
- 大型项目需要自定义异常,小项目则不然。
- 自定义异常需要保持合理的【异常继承体系】。
- 简单实现
-
自定义BaseException作为自定义的“根异常”。
-
BaseException 继承自 RuntimeException 且提供多个构造方法。
-
由 BaseException 派生其他异常。
// 必须将调用父类 super 方法,保护异常案发现场 public class BaseException extends RuntimeException { public BaseException() { super(); } public BaseException(String msg, Throwable cause) { super(msg, cause); } public BaseException(String msg) { super(msg); } public BaseException(Throwable cause) { super(cause); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)