Java 抛出选中异常与抛出包装的RuntimeException

Java 抛出选中异常与抛出包装的RuntimeException,java,exception,runtimeexception,Java,Exception,Runtimeexception,在很多地方,我会得到一些检查过的异常,比如IOException、ParseException、jsoneexception等。我必须做出两个选择之一- 通过在方法签名的末尾添加抛出来抛出相同的异常 将选中的异常包装到RuntimeException(或某些自定义实现)中,然后抛出它,这样调用者就不必到处添加throws子句并检查异常 在第一种情况下,我将不得不到处抛出,但我的客户可以通过捕获checkedException并继续工作来决定不死。然而,在第二种情况下,RuntimeExcepti

在很多地方,我会得到一些检查过的异常,比如IOException、ParseException、jsoneexception等。我必须做出两个选择之一-

  • 通过在方法签名的末尾添加抛出来抛出相同的异常

  • 将选中的异常包装到RuntimeException(或某些自定义实现)中,然后抛出它,这样调用者就不必到处添加throws子句并检查异常

  • 在第一种情况下,我将不得不到处抛出,但我的客户可以通过捕获checkedException并继续工作来决定不死。然而,在第二种情况下,RuntimeException实际上可能会迫使客户机失败,因为人们通常不会在任何地方捕获通用/RuntimeException。另外,使用第二种方法可以更容易地使用Java8Lambdas,因为它不能很好地处理已检查的异常


    两者中哪一个更受欢迎?为什么?有没有更好的做法可以遵循?

    有两种例外情况:调用可以预期的例外情况和原则上意外的例外情况(应用程序代码可能无法以有意义的方式解决)。对于第一类(例如,文件操作的IOException),检查异常(在方法签名的末尾带有“throws”)非常好

    对于第二种情况,我认为出于您声明的原因(不必到处添加抛出),可以将其封装在RuntimeException中。所有软件都应该准备好在顶层捕获运行时异常,作为“最后一道防线”,或者他们接受运行时异常将结束程序(例如,对于命令行应用程序来说,这通常是可以接受的)

    第二种情况的示例是缺少必要的配置文件。我会将IOException作为RuntimeException重新引用

    顺便说一下,还有第三种常用方法:抛出特定于应用程序的异常。例如,此异常可以称为“MyConfiguration异常”。我认为,只有当应用程序能够捕获此异常并智能地处理它时,这才有用。

    (1)通过在方法签名末尾添加抛出来抛出相同的已检查异常:

    如果调用方可以从异常中恢复,或者至少有 在此基础上作出一些决定/取得一些进展

    (2)将选中的异常包装到RuntimeException(或某些自定义实现)中:

    如果调用方无法恢复(中的大多数异常),请使用此选项 Spring/Hibernate框架遵循这种模式)


    还有第三个选项,即抛出相同的选中异常,但“软化”它。CheckedExceptions只在编译时强制执行,通过将异常强制转换为可丢弃的,您可以安全地抛出它,而无需编译器抱怨。下面是一个示例实现(在我参与的库中提供,或者您可以复制并粘贴:)

    根据Andy Turner的评论更新简化的例外情况

    public class ExceptionSoftener {
    
    
       public static <T extends Throwable> T softenedException(final T e) {
           uncheck(e);
           return e; //never reached.
       }
    
       private static <T extends Throwable> void uncheck(Throwable throwable) throws T {
           throw (T) throwable;
    
       }
    
     }
    
       public void methodThrowsIOException(){      
           throw ExceptionSoftener.softenedException(new IOException("checked exception, but no declaration required!"));
       }
    
    公共类例外情况{
    公共静态T软化异常(最终T e){
    取消选中(e);
    返回e;//从未到达。
    }
    私有静态void uncheck(Throwable Throwable)抛出T{
    扔(T)可扔;
    }
    }
    public void methodThrowsIOException(){
    抛出ExceptionSoftener.SofteedException(新IOException(“已检查的异常,但不需要声明”);
    }
    
    。通过JavaDoc或throws子句记录可以调用什么,因此如果客户机想要处理它,他们可以这样做。@wero这是一种非常糟糕的做法,因为它将包括您当前没有抛出的异常,但是如果您的实现发生更改,则会出现异常,并且应该以特定的方式处理。一个明显的例子就是“打断”。“为什么你认为我是个伪君子?”你只是说你不同意吗?我不是伪君子(至少在这一点上):我实践我所主张的。@wero当然也有抛出
    异常
    有用的情况:例如,在
    可调用
    接口中,任何代码都可以执行,任何异常都可以抛出。这就是
    抛出异常的原因
    所说的:为任何事情做好准备。在代码中使用它只会引发特定的异常,因为您不想花费更多的击键来准确地告诉调用者他们可能会遇到什么问题,这显然是懒惰,并且通过消除调用者可能遇到的问题的界限,大大增加了调用者的负担@wero…此外,他们可能遇到的问题类型可以在没有任何迹象表明他们的处理代码需要更改的情况下更改:这就是我所说的一种非常糟糕的做法。
    Thrower
    类在这里是必要的吗:为什么不直接声明
    private static void uncheck(Throwable t)throws t
    exceptions oftener
    内部,取消选中(e)?我认为最好将
    throwSoftenedException
    RuntimeException
    的返回类型改为
    void
    ,这样您就可以使用
    throwSoftenedException.throwSoftenedException(…)
    向编译器指示执行将在该行停止。这是您的意思吗?-公共静态R-throwSoftenedException(最终T-e);如果我们试图做的是允许这样的代码,那么它必须是一个新类型,而不是T:-return throwSoftenedException(new IOException());这将停止编译器抱怨某个方法没有返回某些内容(实际上抛出了异常)。那也行。我将使用该选项添加另一个方法。这无疑是在进一步欺骗编译器:)为什么不能