异常是程序运行时“意外但可预期”的中断事件,如文件被删、除零、网络超时;它编译通过但运行抛出nullpointerexception等,属throwable下的exception分支,分受检(如ioexception)与非受检(如runtimeexception)两类。

什么是异常?不是语法错误,也不是逻辑bug
异常是程序运行中“意外但可预期”的中断事件,比如读文件时文件突然被删、除零、网络请求超时。它和编译报错(如少分号)、或业务逻辑写错(如把加法写成减法)有本质区别:异常发生在 运行时,且 Java 能通过类型系统明确告诉你“这里可能出事”。
关键判断标准:如果代码能编译通过,但一跑就崩,并抛出类似 java.lang.NullPointerException 或 java.io.FileNotFoundException 这样的堆栈信息——那就是异常。
Throwable 之下只有两条路:Error 和 Exception
所有异常都继承自 Throwable,但它只允许你走其中一条路:
-
Error:JVM 自己扛不住的事,比如OutOfMemoryError(堆爆了)、StackOverflowError(递归太深)。你 catch 它也没用,别费劲处理; -
Exception:这才是你要管的。它又分两派:
-
RuntimeException及其子类(如NullPointerException、ArrayIndexOutOfBoundsException):编译器不管,爱抛不抛,你爱抓不抓; - 其他
Exception子类(如IOException、ParseException):编译器强制你表态——要么try-catch,要么在方法签名里写throws,否则直接编译失败。
怎么选:catch 还是 throws?别硬吞,也别全扔给上层
遇到异常,第一反应不该是“赶紧 try-catch 包住”,而是问自己:
- 这个异常我当前这一层能真正恢复吗?比如读配置失败,可以 fallback 到默认值 → 那就
catch并处理; - 还是我只是个工具方法,根本不知道调用者想怎么应对?比如一个
parseJson(String)方法,解析失败只能告诉调用者“这串不是合法 JSON”,不该自己打印日志然后返回 null → 那就声明throws JsonParseException; - 最危险的是“空 catch”:
catch (Exception e) { },等于把警报静音,问题会悄悄蔓延到更上层,排查成本翻倍。
catch (Exception e) 或 catch (Throwable t) 这种大而化之的写法。它会掩盖真实问题类型,比如把 InterruptedException 和 IOException 一起吞掉,导致线程中断信号丢失——这是并发场景里的经典陷阱。
资源管理别靠 finally,优先用 try-with-resources
老写法:InputStream 打开后在 finally 里 close(),看似稳妥,但一旦 close() 自己也抛异常,就会覆盖前面的主异常,还容易漏写 null 判断。
新写法:只要资源实现 AutoCloseable(比如 FileInputStream、Connection、Scanner),就直接用:
try (FileInputStream fis = new FileInputStream("data.txt")) {<br> // 读取逻辑<br>} catch (IOException e) {<br> // 只处理业务级 IO 异常<br>}Java 会自动确保 fis.close() 执行,且不会掩盖原始异常。这是 JDK 7 引入的语法糖,不是可选项,是现在写法的底线。
立即学习“Java免费学习笔记(深入)”;









