如果我在Exception上调用getCause(),为什么我必须处理Throwable

时间:2015-08-05 16:43:08

标签: java exception-handling

如果我在Throwable上调用getCause(),我会在Java中设计一个Exception对象。

我了解getCause()只是继承自Throwable,我知道Throwable可以是ErrorException,但通常是程序员应该只在Exception级别上工作而不处理Throwable / Error类。

例如,在Java异常层次结构设计中,getCause()类中不包含Exception会返回Exception对象的原因是什么?

以下是 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);
        }
    }
}

书中说:

  

...但也因为ExecutionException的原因作为Throwable返回,这很难处理......

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);
}

3 个答案:

答案 0 :(得分:4)

<category android:name="android.intent.category.DEFAULT" /> getCause中定义的方法,在Throwable中只是继承Exception的原因只是Throwable(可能是ThrowableException)。

IMO,有一个方法,比如Error,只返回一个getCauseAsException,如果有的话,因为原因异常并不真正有用。如果您只关注Exception而不关注getCause(),则可以直接调用Exception并检查它是否是Exception的实例。

答案 1 :(得分:2)

首先,如果您的类型具有一些子类型,并且它们的行为实际上是相同的,那么在父类中定义方法是有意义的。基本上,设计师所说的是:“Throwable可以有一个原因,也是一个可抛出的原因,你可以得到那个原因”。您可以在ExceptionError中执行此操作,因为它们都恰好是扔掉的。

现在,Throwable层次结构自Java 1.0以来就存在,并且那里不存在泛型。现在你可能已经定义了这样的行为:

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

您可以将ModernException定义为extends ModernThrowable<ModernException>然后您可以获得您期望的那种行为。

但是当时这个设计并不存在,所以你得到一个Throwable,你必须投出它。这就是过去的工作方式,你必须保持向后兼容性。

但实际上......听起来似乎有道理,这不是真的。至少,这不是全部真相。

Error作为Exception的原因是完全可以的。看看javax.management.RuntimeErrorException。当您使用代理时,您可能会得到Error,在这些特殊情况下,不应该让您立即中止系统。所以你把它作为这个特殊异常的原因。因此,您的getCause()实际上会从Error返回Exception

因此,如果它不是这样设计的,你就必须经历箍 - 只有这个特殊例外的原因才有专门的方法。

答案 2 :(得分:0)

程序员在实现应用程序时通常在异常级别工作。但请记住,例如,JVM也是用Java实现的,在这种情况下,程序员也应该在Throwable / Error级别工作。

因此,除了语言设计本身的问题之外,您应该在异常层次结构树中的哪个级别更多地处理您正在实施的系统域的问题。因此,从语言设计的角度来看,在Throwable类中提供getCause方法是完全合理的,Throwable类是层次结构树的根。由于Exception类从其超类继承此方法,因此在某些特定域中,您不必使用不同的返回类型提供相同的方法,因为在某些特定的域中,您不应该使用Throwable实例