简体   繁体   English

如果在异常上调用getCause(),为什么还要处理Throwable

[英]Why do I have to deal with Throwable if I invoke getCause() on an Exception

It is designed in Java that I get a Throwable object if I invoke getCause() on an Exception . 它是用Java设计的,如果我在Exception上调用getCause() ,则会得到Throwable对象。

I understand that getCause() is simply inherited from Throwable and I know that Throwable can be either an Error or an Exception , but a programmer generally should work only on the Exception level without dealing with Throwable / Error classes. 我知道getCause()只是从Throwable继承的,我知道Throwable可以是ErrorException ,但是程序员通常只应在Exception级别上工作,而不处理Throwable / Error类。

What was the reason in the Java exception hierarchy design to, for example, not include getCause() in the Exception class that would return an Exception object? 例如,在Java异常层次结构设计中是什么原因导致在Exception类中不包含getCause()会返回Exception对象?

Here is an illustration of the inconvenience taken from Java Concurrency In Practice (Brian Goetz): 这是从Java Concurrency in Practice (Brian Goetz)中摘录的不便之处:

public class Preloader {
    private final FutureTask<ProductInfo> future =
        new FutureTask<ProductInfo>(new Callable<ProductInfo>() {
            public ProductInfo call() throws DataLoadException {
                return loadProductInfo();
            }
        });
    private final Thread thread = new Thread(future);
    public void start() { thread.start(); }
    public ProductInfo get()
        throws DataLoadException, InterruptedException {
        try {
            return future.get();
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof DataLoadException)
                throw (DataLoadException) cause;
            else
                throw launderThrowable(cause);
        }
    }
}

It is said in the book: 书中说:

...but also because the cause of the ExecutionException is returned as a Throwable , which is inconvenient to deal with... ...还因为ExecutionException的原因作为Throwable返回,因此不方便处理...

And in launderThrowable() it is dealt with rethrowing Error right away (because we don't want to deal with it) and returning RuntimeException : launderThrowable()它立即处理Error (因为我们不想处理它)并返回RuntimeException

public static RuntimeException launderThrowable(Throwable t) {
    if (t instanceof RuntimeException)
        return (RuntimeException) t;
    else if (t instanceof Error)
        throw (Error) t;
    else
        throw new IllegalStateException("Not unchecked", t);
}

getCause is a method defined in Throwable , and simply inherited in Exception . getCause是在Throwable定义的Throwable ,并在Exception简单地继承 The cause of a Throwable is simply a Throwable (it could be an Exception or an Error ). Throwable的原因仅仅是Throwable (可能是ExceptionError )。

IMO, having a method, say getCauseAsException , that just returns an Exception if any as the cause exception is not really useful. IMO有一个说getCauseAsException的方法,如果有任何原因,它仅会返回一个Exception ,因为cause异常并不是真正有用的。 You could simply invoke getCause() and check if it's an instance of Exception if you're just concerned with Exception and not Error s. 如果您只关心Exception而不是Error则可以简单地调用getCause()并检查它是否是Exception的实例。

First, if you have a type that has a few subtypes, and their behavior is really the same, it makes sense to define the methods at the parent class. 首先,如果您的类型具有几个子类型,并且它们的行为确实相同,那么在父类中定义方法是有意义的。 Basically, what the designers are saying is: " Throwable can have a cause, which is also a throwable, and you can get that cause". 基本上,设计师们说的是:“ Throwable可以有一个原因,这也是一个抛出,你可以得到的原因”。 And you can do that in both Exception and Error because they both happen to be throwables. 而且您可以在ExceptionError中都这样做,因为它们都碰巧是可抛出的。

Now, the Throwable hierarchy exists since Java 1.0, and generics didn't exist there. 现在, Throwable层次结构从Java 1.0开始就存在,并且泛型在那里不存在。 Nowadays you might be able to have defined the behavior like this: 如今,您可能已经可以定义如下行为:

class ModernThrowable<T extends ModernThrowable<T>> {
    T getCause() {...}
}

And you could define ModernException as extends ModernThrowable<ModernException> and then you could get the sort of behavior that you expect. 然后,您可以将ModernException定义为extends ModernThrowable<ModernException> ,然后您可以得到所需的行为。

But this design didn't exist back then, so you get a Throwable back, and you have to cast it. 但是这种设计当时还不存在,因此您获得了Throwable支持,因此必须进行转换。 That's how things used to work and you have to keep backward compatibility. 这就是过去的工作方式,您必须保持向后兼容性。

But actually... as plausible as this may sound, this is not true . 但是实际上……听起来可能如此这是不正确的 At least, it's not the whole truth. 至少,这不是全部。

It is perfectly OK to get an Error as the cause of an Exception . 得到Error作为Exception的原因是完全可以的。 Take a look at javax.management.RuntimeErrorException . 看一看javax.management.RuntimeErrorException When you are working with an agent, you might get an Error , which in these special circumstances, should not cause you to abort the system immediately. 当您使用代理程序时,您可能会收到Error ,在这些特殊情况下,该Error不应导致您立即中止系统。 So you put it as the cause of this special Exception. 因此,您将其作为此特殊Exception的原因。 And thus, your getCause() will actually return an Error from an Exception . 因此,您的getCause()实际上会从Exception返回一个Error

So if it wasn't designed like this, you would have to go through hoops - have a specialty method just for the cause of this particular exception. 因此,如果它不是这样设计的,那么您就必须经过一番考验-专门针对这种特殊异常的原因使用一种特殊方法。

Programmers generally work at the Exception level when they are implementing applications. 程序员在实现应用程序时通常在异常级别工作。 But remember that the JVM, for instance, is also implemented in Java and, in this context, programmers should work at the Throwable/Error level too. 但是请记住,例如,JVM也是用Java实现的,在这种情况下,程序员也应该在Throwable / Error级别上工作。

So the question of at which level in the exception hierarchy tree you should work its more of an issue of the domain of the system you're implementing, than an issue of the language design itself. 因此,在异常层次结构树的哪个级别上应该解决的问题更多是要实现的系统域问题,而不是语言设计本身问题。 So it makes perfect sense from a language design perspective to provide the getCause method in the Throwable class, which is the root of the hierarchy tree. 因此从语言设计的角度来看,最好在Throwable类中提供getCause方法,该类是层次结构树的根。 Since the Exception class inherits this method from its superclass, it's not necessary to provide the same method with a different return type just because in some specific domains you don't/shouldn't work with Throwable instances. 由于Exception类从其父类继承了此方法,因此不必仅在某些特定域中就不/不应使用Throwable实例来提供具有不同返回类型的相同方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM