使用Unsafe.getUnsafe()。throwException抛出异常

时间:2010-12-07 10:51:16

标签: java exception unsafe

我在java.lang.Class #newInstance0:

中遇到了一些有趣的代码
// Run constructor
try {
    return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
    Unsafe.getUnsafe().throwException(e.getTargetException());
    // Not reached
    return null;
}

查看Unsafe.getUnsafe().throwException声明。它看起来像是从一个没有声明要抛出它的方法抛出一个已检查的异常!

他们为什么这样做?
如果Sun开发人员可以使用这种技术,我们也可以这样做吗?

5 个答案:

答案 0 :(得分:3)

  

为什么他们这样做?

我不完全确定,但我希望有一个非常好的理由。 (当您向下钻取图层时,反射调用涉及一些非常棘手的事情......)

  

如果Sun开发人员可以使用这种技术,我们也可以这样做吗?

我会说不......除非你有一个非常非常好的理由。抛出已检查异常而不声明它们的方法违反了最少惊喜的原则。想想可能需要在凌晨3点在关键生产系统中调试代码的穷人。

只是因为某些Sun工程师认为在某个特定环境中某些东西是个好主意,并不一定能让它成为一个好主意。

答案 1 :(得分:3)

使用Java和泛型,您可以从类型擦除中获益,只需使用这个简单的技巧抛出任何异常:

public class Test {
    public static void main(String[] args) {
        doThrow(new SQLException());
    }

    public static void doThrow(Exception e) {
        Test.<RuntimeException> doThrow0(e);
    }

    @SuppressWarnings("unchecked")
    public static <E extends Exception> void doThrow0(Exception e) throws E {
        throw (E) e;
    }
}

有点可怕,但是......

答案 2 :(得分:2)

Don Schwarz在Avoiding Checked Exeptions上有一个有趣的博客。谢谢分享。

答案 3 :(得分:1)

使用Unsafe类的问题在于它仅供内部使用,并且没有已定义的接口,并且IS对于不同的平台是不同的。

您可以使用标准调用实现相同的功能。 (虽然已弃用)

Thread.currentThread().stop(checkedException);

答案 4 :(得分:1)

Sun通常会这样做,以允许直接从Class.newInstance()抛出已检查的异常,而不是将其包装在InvocationTargetException中或在签名上声明throws Exception

这是一个有趣的&#34;设计决策,因为它与其他地方的模式不同 - 例如,Constructor.newInstance()将在InvocationTargetException中包装任何构造函数异常。

&#34;福利&#34;据说提供的是:

  1. 以原始类型直接捕获构造函数异常的能力;和

  2. 避免newInstance()需要声明throws Exception并且调用者捕获异常。

  3. 缺点是:

    1. 未声明已检查的异常。这消除了已检查异常的主要优点/目的,并且可能产生警告,由于未声明已检查的异常,catch块无法访问。
    2. 这可能是您在代码中使用的模式吗?对我来说这似乎不太可能。它似乎最有可能适用于通用/框架代码,其中由框架包装的客户端代码可能会抛出已检查的异常。然后,如果你希望将已检查的异常传播出去而不声明它们可以被抛出,那么它将是唯一可取的。对我来说这是值得怀疑的。

      包装客户端代码的大多数Java框架方法都是以三种异常范例之一设计的:

      1. 纯运行时异常,或
      2. 声明throws Exception允许完整的已检查例外情况,或
      3. 在包装中重新抛出&#39;方法(考虑使用未经检查的异常作为包装器)。
      4. 这种特殊的Class.newInstance方法非常不寻常,并且通过不声明可能被抛出的已检查异常,它绕过/避免了已检查异常的唯一真正好处。

        一般来说,向运行时而不是检查异常进行了重大转变,我不推荐Unsafe.throwException()(也不推荐上面的Lukas提到的&#34;泛型黑客&#34;)

        对于应用程序代码,我建议尽可能使用运行时异常&amp;声明抛出的异常类型。对于框架代码,请考虑上面的三个范例,并优先考虑运行时异常。

        背景:http://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/