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 = Object::toString;
String s = toStringFunc.apply(o);
System.out.println(s);
}
}
이 코드는이 발생합니다 NullPointerException
슬로우, 포함하는 행에서보고 toStringFunc.apply(o)
.
이것은 사소한 예제이므로 쉽게 알 수 o == null
있지만 일반적으로이 코드 줄에서 NPE를 던지는 이유를 이해할 수 있습니다 toStringFunc
. 해당 줄에서 역 참조되는 유일한 변수가 null이 아닙니다.
일반적으로 가장 깊은 스택 추적 항목을 살펴보고 해당 행에서 역 참조 된 변수를 찾습니다. 스택 추적이 다음과 같을 때 이것이 가능하지 않다는 점이 맞습니다.
Exception in thread "main" java.lang.NullPointerException
at Playground.main(Playground.java:9)
문제는 main
메서드 의이 줄에서 실제 역 참조가 발생하지 않았다는 것입니다. apply
구현이 JRE 생성 클래스의 일부이고 스택 프레임이 추적에서 생략 된 호출 된 메소드 내에서 발생 합니다.
항상 그런 것은 아닙니다. JDK-8025636 : Hide lambda proxy frames in stacktraces 의 결과입니다 . 이 변경 사항은 이 Q & A 에서도 논의되었습니다 .
숨김은 람다 식에 대해 원활하게 작동합니다.
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);
}
}
대신 스택 추적은 다음과 같습니다.
Exception in thread "main" java.lang.NullPointerException
at Playground.lambda$main$0(Playground.java:8)
at Playground.main(Playground.java:9)
호출자 ( main
)와 피 호출자 ( ) 사이에 관련이없는 생성 된 메서드 lambda$main$0
가 생략 된 상태에서 역 참조가 발생한 정확한 위치를 보여줍니다 .
안타깝게도 다른 가시적 인 메서드의 도움없이 대상 메서드가 직접 호출되는 메서드 참조에서는 원활하게 작동하지 않습니다. 이는 특히 호출 자체가 실패하여 대상 메서드가 추적에없는 경우 (예 : 수신자 인스턴스가) 인 경우에 역효과를 null
냅니다. null
대상 메서드를 호출하기 전이나 후에 생성 된 코드에서 unbox를 시도 할 때 유사한 문제가 발생할 수 있습니다 .
한 가지 해결책은
-XX:+UnlockDiagnosticVMOptions -XX:+ShowHiddenFrames
스택 프레임 숨기기를 비활성화하는 옵션 으로 JVM을 실행하는 것 입니다. 이것은 리플렉션과 같은 다른 바인딩 코드에도 영향을 미치기 때문에 훨씬 더 긴 스택 추적을 유발할 수 있습니다. 따라서 특정 예외가보고 된 장소에서 발생하지 않고 숨겨진 프레임에서 발생했다고 의심되는 경우에만이 옵션을 사용할 수 있습니다. 이 옵션을 원래 코드와 함께 사용하면 다음이 생성됩니다.
Exception in thread "main" java.lang.NullPointerException
at Playground$$Lambda$1/321001045.apply(<Unknown>:1000001)
at Playground.main(Playground.java:9)
클래스 및 메서드의 이름은 다를 수 있지만 생성 된 코드로 인식 할 수 있습니다. 이 스택 추적에서 main
9 행 에서 역 참조되는 변수가 아니라 호출에 전달 된 인수 중 하나가 여야 한다는 결론을 내릴 수 있습니다 null
.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다