Java 8 method reference to class instance method NPE

前端 未结 2 1147
清酒与你
清酒与你 2021-01-29 15:45
import java.util.function.Function;

public class Playground {
    public static void main (String[] args) {
        Object o = null;
        System.out.println(o);
             


        
相关标签:
2条回答
  • 2021-01-29 16:32

    Normally, you would look at the deepest stack trace entry to find out which variable has been dereferenced in the corresponding line. You are right in that this is not possible here when the stack trace looks like

    Exception in thread "main" java.lang.NullPointerException
            at Playground.main(Playground.java:9)
    

    The problem is that in this line in the main method, the actual dereferencing did not happen. It happens within the invoked apply method whose implementation is part of a JRE generated class and whose stack frame has been omitted from the trace.

    This was not always the case. It’s the result of JDK-8025636: Hide lambda proxy frames in stacktraces. This change has been discussed in this Q&A as well.

    The hiding works smoothly for lambda expressions, e.g. if you used

    import java.util.function.Function;
    
    public class Playground {
        public static void main (String[] args) {
            Object o = null;
            System.out.println(o);
            Function<Object, String> toStringFunc = obj -> obj.toString();
            String s = toStringFunc.apply(o);
            System.out.println(s);
        }
    }
    

    instead, the stack trace looked like

    Exception in thread "main" java.lang.NullPointerException
            at Playground.lambda$main$0(Playground.java:8)
            at Playground.main(Playground.java:9)
    

    showing the exact place where the dereferencing happened while the irrelevant generated method mediating between the caller (main) and the callee (lambda$main$0) has been omitted.

    Unfortunately, this doesn’t work that smooth for method references where the target method is invoked directly without the aid of another visible method. This backfires especially in cases where the target method is not in the trace as the invocation itself failed, e.g. when the receiver instance is null. Similar problems may occur when an attempt to unbox null happened in the generated code before or after the invocation of the target method.

    One solution is to run the JVM with the options
    -XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames to disable the hiding of stack frames. This may cause much longer stack traces as it also affects other binding code, e.g. for Reflection. So you may only use this option when you have the suspicion that a certain exception did not happen at the reported place, but at a hidden frame. Using this option with you original code yields:

    Exception in thread "main" java.lang.NullPointerException
            at Playground$$Lambda$1/321001045.apply(<Unknown>:1000001)
            at Playground.main(Playground.java:9)
    

    The name of the class and method may vary, but it’s recognizable as generated code. From this stack trace, you can conclude that not a variable being dereferenced at main, line 9, but rather one of the arguments passed to the invocation must have been null.

    0 讨论(0)
  • 2021-01-29 16:35

    when you do

    toStringFunc.apply(o);
    

    this is the same that

    o.toString()
    

    that's why you get a NullPointerException so, you must ensure that your Object is not null.

    0 讨论(0)
提交回复
热议问题