首页 > 编程语言 >Java Checked Exception 的是与非

Java Checked Exception 的是与非

时间:2023-04-02 21:56:46浏览次数:51  
标签:Exception Java FileNotFoundException FileInputStream new Checked 异常

结论

Java Checked Exception是一个设计错误,初衷很美好,现实很糟糕。

设计的初衷

把方法可能抛出的异常,显示地声明在方法定义中,比如FileInputStream的构造函数可能会抛出FileNotFoundException:

public FileInputStream(String name) throws FileNotFoundException {
    this(name != null ? new File(name) : null);
}

从而

  1. 明确列出有哪些可能出现的异常需要被处理,表意更清晰,可读性更好
  2. 编译器也会强制调用方做异常处理(声明的异常不是RuntimeException)

糟糕的现实

然而美好的设计初衷落到现实的代码里,往往可能变成下面这样:

  1. 一路向上的异常声明
public void readFile() throws FileNotFoundException {
    FileInputStream fileInputStream = new FileInputStream("a.txt");
    // ...
}

调用链路长,异常多时,是一种灾难。

  1. 抛出被RuntimeException包装的异常
public void readFile() {
    try {
        FileInputStream fileInputStream = new FileInputStream("a.txt");
        // ...
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
}

这种实现更常见,这样以来Checked Exception形同虚设。

  1. 版本升级,方法实现有变动,声明的Checked Exception也需要改变时,需要新的方法定义
    假如FileInputStream构造器改变了实现,需要在声明上增加AccessDeniedException:
public FileInputStream(String name) throws FileNotFoundException, AccessDeniedException {
    this(name != null ? new File(name) : null);
    // ... 实现上的变动
}

直接像上面这样改方法声明是无法实现的,因为无数的上游调用方只处理了FileNotFoundException,会有兼容问题,只能通过其他方式。升版困难,扩展性差。

为什么有设计与实现的背离

对于上述现实里的现象1和现象2,产生这种背离的一般原因都是:方法的调用方没有异常处理的能力
文件读取、网络调用这类服务的调用方可能处于应用结构的下层,而对不同的异常做出不同的处理决策往往是较上层组件的能力(展示给用户友好的异常提示、自动容灾策略等)。

对于现实里的现象3,方法升级时,仅仅为了增加异常声明就大费周章升级接口,实在不划算;不过不添加异常声明,改用RuntimeException却又显得不统一。左也不是,右也不是。

我该怎么做

一言以蔽之,日常开发中,避免使用Checked Exception。

碰到库中Checked Exception时,可以

  1. 用上文所述抛出RuntimeException包装的异常,Throwable#getCause() 获取原异常:
try {
    new Demo().readFile();
} catch (Exception exception) {
    Throwable cause = exception.getCause();
    if (cause instanceof FileNotFoundException) {
        // instanceOf 判断原异常类型分别处理
        // ...
    }
}
  1. 不关心原异常具体类型时,使用lombok的@SneakyThrows
@lombok.SneakyThrows
public void readFile() {
    FileInputStream fileInputStream = new FileInputStream("a.txt");
    // ...
}

一些参考

标签:Exception,Java,FileNotFoundException,FileInputStream,new,Checked,异常
From: https://www.cnblogs.com/zero-czy-one/p/17281509.html

相关文章

  • JAVA - IO 流
    FileInputStreamimportjava.io.FileOutputStream;importjava.io.IOException;publicclassFileOutPutStreamDemo{/*FileOutputStream使用细节:1.write方法写出的数字:是ASCCI表中字符对应的数字,因此a=>972.创建FileOutputStream对象时“E:\java......
  • Java学习笔记14
    1.Arrays类​ Arrays类包含用于操作数组的各种方法(如排序和搜索)。该类没有构造函数,直接使用类名.方法名()的方法调用需要的方法。常用方法方法作用publicstaticStringtoString(数组)把数组拼接成一个字符串publicstaticintbinarySearch(数组,查找的元素)二......
  • 从 JDK 9 到 19,认识一个新的 Java 形态(内存篇)
    前言在JDK9之前,Java基本上平均每三年出一个版本。但是自从2017年9月份推出JDK9到现在,Java开始了疯狂更新的模式,基本上保持了每年两个大版本的节奏。从2017年至今,已经发布了一个版本到了JDK19。其中包括了两个LTS版本(JDK11与JDK17)。除了版本更新节奏明显加快之......
  • JNDI(Java Naming and Directory Interface–Java命名和目录接口)
    JNDI(JavaNamingandDirectoryInterface,Java命名和目录接口)为应用程序提供了一种通过网络访问远程服务的方式。本节我们学习如何通过JNDIAPI注册和访问JDBC数据源对象。读者如果需要了解更多JNDI相关细节,则可参考JNDI规范文档。JNDIAPI的命名服务可以把一个逻辑名称和一个具......
  • java使用模块后,用maven打包时,需要保护的maven插件
    <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version><configuration><release>11</release><......
  • java流
    流运算map和flatMapmap函数接收一个函数作为参数,将该函数应用于流中的每个元素,并返回一个新的流。例如,我们可以通过map函数将流中的每个元素都加上1:List<Integer>numbers=Arrays.asList(1,2,3,4);List<Integer>incrementedNumbers=numbers.stream()......
  • java -- static, 内部类, 权限, 参数传递
    static关键字static是静态修饰符,一般修饰成员。被static修饰的成员属于类,不属于单个这个类的某个对象。static修饰的成员被多个对象共享。static修饰的成员属于类,但是会影响每一个对象。被static修饰的成员又叫类成员,不叫对象的成员。static特点被static修饰的成员变量属于类,不......
  • 有关哈希表简单的散列函数实现-Java实现
    其实现不难,所以直接贴代码:1packagedataSrtuct;23importjava.util.ArrayList;4importjava.util.LinkedList;56publicclassHashTab{7publicstaticvoidmain(String[]args){8hashTablehashT=newhashTable(10);9......
  • leetcode 394.字符串解码 Java
    394.字符串解码给定一个经过编码的字符串,返回它解码后的字符串。编码规则为:k[encoded_string],表示其中方括号内部的encoded_string正好重复k次。注意k保证为正整数。你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。此外......
  • Java SPI机制简介
    在JDBC4.0版本之前,使用DriverManager获取Connection对象之前都需要通过代码显式地加载驱动实现类,例如:JDBC4.0之后的版本对此做了改进,我们不再需要显式地加载驱动实现类。这得益于Java中的SPI机制,本节我们就来简单地了解SPI机制。SPI(ServiceProviderInterface)是JDK内置的一......