Java 7多重catch语法支持catch(ExceptionA | ExceptionB),但要求异常类型互不继承且均为检查型异常或RuntimeException子类,共享同一处理逻辑并保留完整栈信息。

Java 7多重catch语法能写成catch(ExceptionA | ExceptionB)吗
能,但仅限于**编译期已知互不继承的检查型异常(checked exception)或运行时异常(RuntimeException)子类**,且它们必须是**并列关系**——不能一个是另一个的父类或子类。Java 编译器会拒绝catch(IOException | Exception)这种写法,因为Exception是IOException的父类。
- ✅ 正确:
catch(NullPointerException | IllegalArgumentException)(二者都继承自RuntimeException,无继承关系) - ✅ 正确:
catch(IOException | SQLException)(都是检查型异常,无继承) - ❌ 报错:
catch(Exception | RuntimeException)(后者是前者的子类) - ❌ 报错:
catch(FileNotFoundException | IOException)(前者是后者的子类)
为什么用|写法比分开写多个catch块更安全
它强制你用**同一个变量名、同一段处理逻辑**去覆盖所有列出的异常类型,避免因复制粘贴导致各catch块逻辑不一致——比如一个写了日志,另一个忘了;或者一个调用了rollback(),另一个没调。
- 共享变量:异常对象统一绑定为
e,类型是这些异常的**最小公共父类**(如catch(A | B)中e类型是A和B最近的共同父类) - 无法单独访问子类型特有方法:如果
A有getErrorCode()而B没有,就不能在catch块里直接调用e.getErrorCode(),会编译失败 - 异常栈信息完整保留:不会像旧写法中“先捕
A再抛B”那样丢失原始堆栈
catch(A | B)在try-with-resources里要注意什么
当try块里既有资源自动关闭,又有多重异常捕获时,**资源关闭过程中抛出的异常可能被压制(suppressed)**,而catch(A | B)只捕获主流程抛出的异常,压制异常得靠e.getSuppressed()手动取——这点很容易漏。
- 示例场景:
try (FileInputStream fis = new FileInputStream("a.txt")) { ... }中,fis.close()失败抛IOException,但主流程已抛SQLException,后者被捕获,前者被压制 - 必须显式检查:
for (Throwable s : e.getSuppressed()) { ... } - 若想统一处理所有异常(包括压制的),别用多重
catch,改用单个catch(Exception e)再自己分发
Java 7多重catch在Android或老JDK上跑不了怎么办
它从Java 7开始支持,但**Android默认最低支持Java 7字节码,可实际能否用取决于编译器和targetSdk**。AGP 4.0+、minSdk ≥ 26 通常没问题;但若用Java 6编译或targetSdk太低,会报multi-catch statement is not supported错误。
立即学习“Java免费学习笔记(深入)”;
- 检查
sourceCompatibility和targetCompatibility是否设为JavaVersion.VERSION_1_7或更高 - Android项目还需确认
compileOptions中sourceCompatibility和targetCompatibility一致 - CI环境容易忽略JDK版本:本地用JDK 8编译成功,CI用JDK 6就直接失败
- 替代方案不是退回去写两个
catch,而是提取共用逻辑到私有方法,保持复用性








