在 NPE 的情况下尝试操作

2022-09-04 21:49:10

请考虑以下代码:

String s = null;
s.toLowerCase();

它抛出一个 NPE:

异常 in thread “main” java.lang.NullPointerException
at pracJava1.Prac.main(Prac.java:7)

问题是:为什么JVM不能同时放置一个帮助器消息说:

线程 “main” java.lang.NullPointerException 中的异常。企图toLowerCase() on null

这在以下情况下很有用,其中行号不足以猜测是否为 null 或 。obj.setName(s.toLowerCase())objs


关于它的可行性,让我们看一下生成的字节码:

      stack=1, locals=2, args_size=1
     0: aconst_null
     1: astore_1
     2: aload_1
     3: invokevirtual #2    // Method java/lang/String.toLowerCase:()Ljava/lang/String;

因此,它可能确实知道,它尝试操作的方法名称。JVM专家,您怎么看?


答案 1

为什么 JVM 不能同时放置一个帮助器消息

首先,JVM可以做到这一点。例如,SAP JVM确实为NullPointerExceptions,ClassCastExceptions等提供了扩展消息

有人要求对HotSpot JVM做同样的事情,但由于@StephenC答案中提到的原因,它们被关闭为Will-Not-Fix。

但是,可以在 JVM TI 代理的帮助下丰富 NullPointerException 消息。

扩展 NPE 消息的示例


答案 2

不这样做的一个可能原因是它可能会破坏旧的Java代码。从一开始,在经典Java的所有实现中,JVM本身抛出的NPE的消息属性都是。null

任何破坏旧应用程序代码的更改都会损害Java的Sun / Oracle业务模型。所有证据表明,Sun / Oracle试图避免这种情况,除非替代方案更糟

(偶尔会犯错误/误判,并且(可以说)对Java进行不必要的“中断”更改。我们看到某些方面由此产生的“愤怒的嚎叫”,我想甲骨文也通过他们的客户联系人获得反馈。

Android“Java”以不同的方式做到这一点。(这表明NPE错误消息在Java中在技术上是可行的)但谷歌不需要担心与旧的经典Java应用程序的兼容性。当用Android替代品替换了大量标准Java SE库时,他们省去了这个问题。


您评论道:

但是Oracle确实多次破坏了兼容性更改,其中api规范没有被破坏(但内部结构当然发生了变化)。如果有人正在解析NPE错误消息,我认为这不是一个足够好的理由:)

这些都是很好的辩论点(也许)。

但是,这一决定不容公开辩论。这是Sun多年前做出的商业决策,甲骨文也选择坚持这一决定。我们不知道真正的原因是什么。你或我对假设推理的看法是无关紧要的。

为了记录在案,这是在2003年提出的RFE(JDK-4834738)。该问题最终于2014年作为WNF(不会修复)关闭。没有给出任何理由(公开)。


推荐