是否可以在 Java 中禁用检查异常?

Posted

技术标签:

【中文标题】是否可以在 Java 中禁用检查异常?【英文标题】:Is disabling Checked Exceptions in Java possible? 【发布时间】:2017-04-09 05:29:11 【问题描述】:

我正在阅读一篇关于 Java 中已检查和未检查异常的文章,并找到了这篇文章/链接: https://projectlombok.org/disableCheckedExceptions.html

根据文章,这只是为 javac 开发的一个 hack。

考虑下面的代码 sn-p:

import java.io.*;
class Example
  
    public static void main(String args[]) throws IOException
    
        FileInputStream fis = null;
        fis = new FileInputStream("myfile.txt"); 
        int k; 

        while(( k = fis.read() ) != -1) 
         
            System.out.print((char)k); 
         
        fis.close();    
    

这里我要写public static void main(String args[]) throws IOException 因为我正在尝试打开一个文件。这里“抛出”子句是必须的。没有它我会得到一个错误。如果我确定我正在打开的文件的存在怎么办。即 myfile.txt 在提到的位置。在某些时候,人们会觉得代码不需要很少的 Checked Exceptions。

Java 是否提供了任何工具来根据需要禁用已检查的异常?

即使做了这么多研究,我也找不到合适的答案。

【问题讨论】:

在编写软件时,您永远无法确定某事是否如您所想,它确实如此。因此,如果出现问题,您应该始终抛出异常。为什么要禁用它们,如果一切正常,它永远不会被抛出,否则它应该被抛出并且你不应该禁用它们 您现在可以确定了,但如果该文件位置发生变化或不可用(例如磁盘/文件系统损坏)怎么办? Java 在这种情况下应该如何反应?它从new FileInputStream("myfile.txt"); 得到了异常,但它不能用它做任何事情......你的代码应该如何进行?它是否应该走得更远并且简单地忽略任何异常?这是自找麻烦。 你怎么能确定? 我的回答是:你不应该。 Checked Exceptions 来自库,告诉程序员有问题需要恢复。程序员可以决定是否可以通过逻辑来恢复错误,或者是否需要通知程序用户并可能要求其做出决定。如果您关闭检查的异常,您决定忽略该错误。这就是最近刚刚使 ExoMars-lander Schiaparelli 坠毁的程序。 有一些工具和库可以简化事情,例如,github.com/google/guava/wiki/… - 但那里的文字也涵盖了为什么这是“有争议的”。 【参考方案1】:

Java 是否提供了任何工具来根据需要禁用已检查的异常?

没有官方设施,但有需要时可以使用的解决方法:

首先,由于 java 中同时存在 checkedunchecked 异常,因此使用 unchecked 异常可能是一种选择。从 RuntimeException 派生的所有异常都未选中:

RuntimeException 是那些的超类 在正常运行期间可以抛出的异常 Java 虚拟机。 方法不需要在其 throws 中声明 条款 RuntimeException 的任何子类可能 在方法执行期间被抛出但未被捕获。

有趣的阅读here,here。

然后是type erasure,它允许在不声明的情况下抛出已检查异常。 这就是项目 lombok 用于@SneakyThrows

import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable 
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) 
    return new String(bytes, "UTF-8");
  

  @SneakyThrows
  public void run() 
    throw new Throwable();
  

谨慎使用:

请注意,直接捕获偷偷摸摸抛出的检查类型是不可能的,因为 javac 不允许您为 try 主体中没有方法调用声明为抛出的异常类型编写 catch 块。

最后,只有编译器关心检查的异常,它根本不是 jvm 的一部分。一旦你过了编译阶段,一切皆有可能。因此直接编写字节码或使用带有checked exceptions disabled 的javac 版本完全绕过它们。

【讨论】:

【参考方案2】:

除了破解编译器之外,没有其他选项可以禁用我所知道的检查异常。如果您不想强制客户端代码处理已检查的异常,您可以做的最好的事情是捕获已检查的异常并在运行时异常中重新抛出它。

【讨论】:

【参考方案3】:

将Manifold 编译器插件与exceptions 插件选项一起使用。它有效地中和了检查的异常。使用此选项,已检查异常的行为类似于未检查异常。没有更多的编译器错误,没有更多的样板 try/catch/wrap/rethrow 废话。适用于 Java 8 - 12。

【讨论】:

以上是关于是否可以在 Java 中禁用检查异常?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 IntelliJ 中为私有方法禁用“可选用作字段或参数类型”检查?

如何使用 Detox 在 React Native 中检查是不是选择或禁用了特定元素?

是否有一个标志可以禁用铬中的子资源完整性检查?

如何检查“显示通知”是启用还是禁用?

如何禁用“返回”某些活动?

Java 在 JTextArea 中禁用水平自动滚动