Boolean.valueOf ()는 때때로 NullPointerException을 생성합니다.


115

이 코드가 있습니다.

package tests;

import java.util.Hashtable;

public class Tests {

    public static void main(String[] args) {

        Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();

        System.out.println("TEST 1");
        System.out.println(modifiedItems.get("item1")); // Prints null
        System.out.println("TEST 2");
        System.out.println(modifiedItems.get("item1") == null); // Prints true
        System.out.println("TEST 3");
        System.out.println(Boolean.valueOf(null)); // Prints false
        System.out.println("TEST 4");
        System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
        System.out.println("FINISHED!"); // Never executed
    }
}

내 문제는 내가 왜 이해하지 못하는 것입니다 테스트 (3)가 잘 작동 (가 인쇄 false및 생산하지 않는 NullPointerException사이에) 시험 4 발생합니다 NullPointerException. 당신은 테스트에서 볼 수 있듯이 12 , null그리고 modifiedItems.get("item1")동등하고 있습니다 null.

동작은 Java 7 및 8에서 동일합니다.


modifiedItems.get ( "item1") 이것은 null입니다. 알고 있지만 valueOf에 전달하는 것이 NPE에서 끝나지 않는다고 가정합니까?
Stultuske

16
@Stultuske : null동일한 함수에 리터럴 을 전달하는 두 줄 위의 단 두 줄만 NPE를 생성 하지 않는다는 점을 감안할 때 유효한 질문입니다 ! 그것에 대한 좋은 이유가 있지만 첫눈에 확실히 혼란 스러워요 :-)
psmears

25
나는 감동. 이것은 내가 몇 년 동안 본 가장 흥미로운 널 포인터 예외 질문입니다.
candied_orange 2010 년

@Jeroen 이것은 그 질문 의 속임수가 아닙니다 . Unboxing이 두 가지 문제에 공통적 인 것은 사실이지만 여기서는 비교가 이루어지지 않습니다. 이 질문의 핵심은 과부하가 해결되는 방식 때문에 발생한다는 것입니다. ==적용 방식과 는 상당히 다릅니다 .
Andy Turner

답변:


178

어떤 오버로드가 호출되는지주의 깊게 살펴 봐야합니다.

  • Boolean.valueOf(null)을 호출하고 Boolean.valueOf(String)있습니다. NPEnull 매개 변수가 제공된 경우에도 는 발생하지 않습니다 .
  • Boolean.valueOf(modifiedItems.get("item1"))호출되어 Boolean.valueOf(boolean)있기 때문에, modifiedItems의 값은 타입 인 Boolean개봉기 변환이 필요. 이후 modifiedItems.get("item1")이며 null, 그것은 그 값이다 개봉기 - 아닌 Boolean.valueOf(...)- NPE가 발생한다.

호출되는 오버로드를 결정하는 규칙은 매우 복잡 하지만 대략 다음과 같습니다.

  • 첫 번째 패스에서는 boxing / unboxing을 허용하지 않고 메서드 일치를 검색합니다 (변수 arity 메서드도 없음).

    • 왜냐하면 nullA에 대한 허용 값은 String아니지만 boolean, Boolean.valueOf(null)에 매칭 Boolean.valueOf(String)이 패스;
    • BooleanBoolean.valueOf(String)또는에 대해 허용되지 Boolean.valueOf(boolean)않으므로이 패스에서에 대해 일치하는 메서드가 없습니다 Boolean.valueOf(modifiedItems.get("item1")).
  • 두 번째 패스에서 메서드 일치를 검색하여 boxing / unboxing을 허용합니다 (하지만 여전히 가변 arity 메서드는 아님).

    • A는 Boolean로 박싱 될 수 boolean있으므로, Boolean.valueOf(boolean)에 대한 매칭 Boolean.valueOf(modifiedItems.get("item1"))이 패스; 그러나 unboxing 변환은 그것을 호출하기 위해 컴파일러에 의해 삽입되어야합니다 :Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (가변 arity 메서드를 허용하는 세 번째 패스가 있지만 처음 두 패스가 이러한 경우와 일치하므로 여기서는 관련이 없습니다)


3
Boolean.valueOf(modifiedItems.get("item1").booleanValue())대신 소스 코드에서 사용하면 코드가 더 명확해질 수 Boolean.valueOf(modifiedItems.get("item1"))있습니까?
CausingUnderflowsEverywhere

1
@CausingUnderflowsEverywhere 실제로는 아닙니다- .booleanValue()표현에 묻혀있는 것을 보는 것은 정말 어렵 습니다. 두 가지 관찰 : 1) auto (un) boxing은 구문상의 혼란을 제거하기위한 Java의 의도적 인 기능입니다. 스스로 할 수는 있지만 관용적이지는 않습니다. 2) 이것은 전혀 도움이되지 않습니다. 확실히 문제가 발생하는 것을 막거나 실패가 발생할 때 추가 정보를 제공하지도 않습니다 (실행 된 코드가 동일하기 때문에 스택 추적이 동일합니다).
Andy Turner

@CausingUnderflowsEverywhere 도구를 사용하여 문제를 강조하는 것이 더 좋습니다. 예를 들어 intellij는 여기서 잠재적 인 NPE에 대해 얻을 수 있습니다.
Andy Turner

13

이후 modifiedItems.get리턴한다 Boolean(이다 하지 스트 String)이며, 사용되는 서명 Boolean.valueOf(boolean)Boolean원시적으로 outboxed됩니다 boolean. 일단 null반환 되면 보낼 편지함이 NullPointerException.


11

메서드 서명

이 메서드 Boolean.valueOf(...)에는 두 가지 서명이 있습니다.

  1. public static Boolean valueOf(boolean b)
  2. public static Boolean valueOf(String s)

귀하의 modifiedItems가치는 Boolean입니다. 당신은 캐스트 수 없습니다 BooleanString그래서 결과적으로 최초의 서명이 선택됩니다

부울 언 박싱

당신의 진술에서

Boolean.valueOf(modifiedItems.get("item1"))

다음과 같이 읽을 수 있습니다.

Boolean.valueOf(modifiedItems.get("item1").booleanValue())   

그러나 modifiedItems.get("item1")반환 null하므로 기본적으로

null.booleanValue()

분명히 NullPointerException


잘못된 표현입니다. 지적 해 주셔서 감사합니다. 귀하의 피드백에 따라 답변이 업데이트되었습니다. 죄송합니다. 글을 쓰는 동안 귀하의 답변을 보지 못했으며 내 답변이 귀하의 것 같습니다. OP에 대한 혼동을 피하기 위해 내 답변을 제거해야합니까?
알 - 유엔

4
내 계정에서 삭제하지 마십시오. 이것은 제로섬 게임이 아닙니다. 사람들은 여러 답변에 찬성 투표를 할 수 있습니다.
Andy Turner

3

Andy가 이미 그 이유를 잘 설명했듯이 NullPointerException:

이것은 Boolean un-boxing 때문입니다.

Boolean.valueOf(modifiedItems.get("item1"))

다음으로 변환됩니다.

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

런타임 에 null이면 throw NullPointerException됩니다 modifiedItems.get("item1").

이제 여기에 다음 클래스를 각각의 프리미티브에 NullPointerExceptionunboxing하면 해당 반환 객체가 null 인 경우 예외가 발생할 수 있다는 점을 한 가지 더 추가하고 싶습니다 .

  1. 바이트-바이트
  2. char-문자
  3. float-부동
  4. int-정수
  5. 길다-길다
  6. 짧음-짧음
  7. double-더블

다음은 코드입니다.

    Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
    System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
    System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
    System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
    System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
    System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
    System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
    System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
    System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" java.lang.NullPointerException

1
"Converted into ... at runtime"컴파일 타임에 변환됩니다.
Andy Turner

0

그것을 이해하는 방법은 언제 Boolean.valueOf(null)호출 되는지 , java는 정확하게 null을 평가하도록 지시받는 것입니다.

그러나 Boolean.valueOf(modifiedItems.get("item1"))가 호출되면 java는 객체 유형 Boolean의 HashTable에서 값을 가져 오도록 지시하지만 Boolean을 예상 했음에도 불구하고 대신 막 다른 골목 (null)을 찾는 Boolean 유형을 찾지 못합니다. NullPointerException 예외는 Java의이 부분의 작성자가이 상황이 프로그래머의주의를 요하는 프로그램에서 잘못되는 인스턴스라고 결정했기 때문에 발생합니다. (의도하지 않은 일이 발생했습니다.)

이 경우 의도적으로 null을 의도했다고 선언하는 것과 객체를 찾으려는 객체 (null)에 대한 누락 된 참조를 찾는 Java의 차이가 더 큽니다.

이 답변에서 NullPointerException에 대한 자세한 정보를 참조하십시오 : https://stackoverflow.com/a/25721181/4425643


누군가가이 답변을 개선하는 데 도움을 줄 수 있다면, 저는 프로그래머가 분명한 의도로 무언가를 모호하지 않고 작성하는 것을 가리키는 단어를 생각하고있었습니다
CausingUnderflowsEverywhere
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.