gpt4 book ai didi

java - JLS 的哪些部分证明能够像未经检查一样抛出已检查异常?

转载 作者:IT老高 更新时间:2023-10-28 21:13:09 25 4
gpt4 key购买 nike

我有 recently discovered and blogged about the fact可以通过 javac 编译器偷偷检查异常并将其抛出到不应抛出的地方。这在 Java 6 和 7 中编译并运行,抛出 SQLException没有 throwscatch子句:

public class Test {

// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}

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

static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}

生成的字节码表明 JVM 并不真正关心已检查/未检查的异常:

// Method descriptor #22 (Ljava/lang/Exception;)V
// Stack: 1, Locals: 1
static void doThrow(java.lang.Exception e);
0 aload_0 [e]
1 invokestatic Test.doThrow0(java.lang.Exception) : void [25]
4 return
Line numbers:
[pc: 0, line: 11]
[pc: 4, line: 12]
Local variable table:
[pc: 0, pc: 5] local: e index: 0 type: java.lang.Exception

// Method descriptor #22 (Ljava/lang/Exception;)V
// Signature: <E:Ljava/lang/Exception;>(Ljava/lang/Exception;)V^TE;
// Stack: 1, Locals: 1
static void doThrow0(java.lang.Exception e) throws java.lang.Exception;
0 aload_0 [e]
1 athrow
Line numbers:
[pc: 0, line: 16]
Local variable table:
[pc: 0, pc: 2] local: e index: 0 type: java.lang.Exception

JVM 接受这是一回事。但我怀疑 Java-the-language 是否应该这样做。 JLS 的哪些部分证明了这种行为?它是一个错误吗?还是 Java 语言的一个隐藏得很好的“特性”?

我的感受是:

  • doThrow0()<E>绑定(bind)到RuntimeExceptiondoThrow() .因此,没有 throwsJLS §11.2 类似的条款doThrow() 中需要.
  • RuntimeExceptionException 的赋值兼容,因此编译器不会生成强制转换(这将导致 ClassCastException )。

最佳答案

所有这些都等于利用了未经检查的转换为泛型类型不是编译器错误的漏洞。如果您的代码包含这样的表达式,则它被明确地设为类型不安全。并且由于检查异常的检查严格来说是一个编译时过程,所以运行时不会中断。

Generics 的作者的回答很可能是“如果您使用未经检查的强制转换,那是您的问题”。

我在您的发现中看到了一些非常积极的东西——突破了检查异常的堡垒。不幸的是,这并不能将现有的受检查异常中毒的 API 变成更好用的东西。

这有什么帮助

在我的一个典型的分层应用项目中,会有很多这样的样板:

try {
... business logic stuff ...
}
catch (RuntimeException e) { throw e; }
catch (Exception e) { throw new RuntimeException(e); }

我为什么要这样做?很简单:没有要捕获的业务值(value)异常;任何异常都是运行时错误的症状。异常必须沿调用堆栈向上传播到全局异常屏障。有了 Lukas 的出色贡献,我现在可以写作了

try {
... business logic stuff ...
} catch (Exception e) { throwUnchecked(e); }

这可能看起来不多,但在整个项目中重复 100 次后, yield 就会累积。

免责声明

在我的项目中,有关于异常的严格纪律,所以这非常适合他们。 这种诡计不能作为一般编码原则采用。在许多情况下,包装异常仍然是唯一安全的选择。

关于java - JLS 的哪些部分证明能够像未经检查一样抛出已检查异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12580598/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com