[java] String switch 문이 null case를 지원하지 않는 이유는 무엇입니까?

Java 7 switch문이 null케이스를 지원하지 않고 대신 던지는 이유가 궁금합니다 NullPointerException. 아래의 주석 처리 된 줄을 참조하십시오 ( 의 Java 자습서 기사에서switch 가져온 예제 ).

{
    String month = null;
    switch (month) {
        case "january":
            monthNumber = 1;
            break;
        case "february":
            monthNumber = 2;
            break;
        case "march":
            monthNumber = 3;
            break;
        //case null:
        default: 
            monthNumber = 0;
            break;
    }

    return monthNumber;
}

이것은 if매번 switch사용 하기 전에 널 체크에 대한 조건을 피했을 것 입니다.



답변

damryfbfnetsi으로 종료 지점 코멘트에, JLS §14.11는 다음과 같은 메모를 가지고 :

null스위치 레이블로 사용하는 것을 금지하는 것은 실행할 수없는 코드를 작성하는 것을 방지합니다. 상기 중간 switch표현은 참조 형식,이다 String또는 박스형 원시 형 또는 열거 형 다음 런타임 에러 발현 평가되는 경우에 발생한다 null런타임. Java 프로그래밍 언어 설계자의 판단에 따르면 전체 switch명령문을 조용히 건너 뛰 거나 default레이블 (있는 경우 ) 뒤에 명령문 (있는 경우)을 실행하도록 선택 하는 것보다 더 나은 결과 입니다.

(강조 광산)

마지막 문장은를 사용할 가능성을 건너 뛰지 만 case null:합리적으로 보이며 언어 디자이너의 의도에 대한 견해를 제공합니다.

구현 세부 사항을 살펴보면 Christian Hujer 의이 블로그 게시물null 에 스위치에서 허용되지 않는 이유 에 대한 통찰력있는 추측 이 있습니다 ( enum스위치가 아닌 스위치에 중점을두고 있음 String).

내부적 switch으로이 문은 일반적으로 tablesswitch 바이트 코드로 컴파일됩니다. 그리고 switch그 사건뿐만 아니라 “물리적”주장 은 ints입니다. 스위치를 켤 int 값은 메서드를 호출하여 결정됩니다 Enum.ordinal(). […] 서수는 0에서 시작합니다.

즉, 매핑 null하는 0것은 좋은 생각이 아닙니다. 첫 번째 열거 형 값의 스위치는 null과 구별 할 수 없습니다. 1에서 열거 형의 서수를 세는 것이 좋은 생각이었을 것입니다. 그러나 그렇게 정의되지 않았고이 정의는 변경할 수 없습니다.

반면 String스위치 다르게 구현되어 상기 enum스위치는 첫 번째 들어오는 기준 인 경우에 동작한다 참조 형식에 스위칭 방법에 대한 선례 null.


답변

일반적으로 null다루기 힘들다. 더 나은 언어는 null.

귀하의 문제는

    switch(month==null?"":month)
    {
        ...
        //case "":
        default: 
            monthNumber = 0;

    }


답변

예쁘지는 않지만 String.valueOf()스위치에서 null String을 사용할 수 있습니다. 을 찾으면 null로 변환하고 "null", 그렇지 않으면 전달한 것과 동일한 문자열을 반환합니다. "null"명시 적으로 처리하지 않으면 default. 유일한주의 사항은 문자열 "null"과 실제 null변수 를 구분할 방법이 없다는 것입니다 .

    String month = null;
    switch (String.valueOf(month)) {
        case "january":
            monthNumber = 1;
            break;
        case "february":
            monthNumber = 2;
            break;
        case "march":
            monthNumber = 3;
            break;
        case "null":
            monthNumber = -1;
            break;
        default: 
            monthNumber = 0;
            break;
    }
    return monthNumber;


답변

이것은 왜 던지는 지 대답하려는 시도입니다. NullPointerException

아래의 javap 명령의 출력은 인수 문자열 case의 해시 코드를 기반으로 선택한 것을 나타내 switch므로 .hashCode()null 문자열 에서이 호출 될 때 NPE를 발생 시킵니다.

6: invokevirtual #18                 // Method java/lang/String.hashCode:()I
9: lookupswitch  { // 3
    -1826660246: 44
     -263893086: 56
      103666243: 68
        default: 95
   }

이것은 Java의 hashCode가 다른 문자열에 대해 동일한 값을 생성 할 수 있습니까? 에 대한 답변을 기반으로 함을 의미합니다 . , 드물기는하지만 여전히 두 개의 케이스가 일치 할 가능성이 있습니다 (동일한 해시 코드를 가진 두 개의 문자열) 아래이 예를 참조하십시오.

    int monthNumber;
    String month = args[0];

    switch (month) {
    case "Ea":
        monthNumber = 1;
        break;
    case "FB":
        monthNumber = 2;
        break;
    // case null:
    default:
        monthNumber = 0;
        break;
    }
    System.out.println(monthNumber);

어느 Javap

  10: lookupswitch  { // 1
              2236: 28
           default: 59
      }
  28: aload_3       
  29: ldc           #22                 // String Ea
  31: invokevirtual #24                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  34: ifne          49
  37: aload_3       
  38: ldc           #28                 // String FB
  40: invokevirtual #24                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  43: ifne          54
  46: goto          59 //Default

당신은 단지 하나의 사건이 생성됩니다 볼 수 있듯이을 위해 "Ea"하고 "FB"있지만, 두 가지로 if조건이 각각의 경우 문자열 일치를 확인합니다. 이 기능을 구현하는 매우 흥미롭고 복잡한 방법!


답변

긴 이야기 짧게 … (그리고 충분히 흥미 로웠기를 바랍니다 !!!)

Enum은 Java1.5 ( 20049 ) 에서 처음 도입되었으며 String 켜기허용 하라는 버그 가 오랫동안 제기되었습니다 ( 95 년 10 월 ). 2004 년 6 월에 해당 버그에 게시 된 댓글을 보면이 버그를 연기 ( 무시 )하고 결국 0부터 시작하는 서수로 ‘열거 형’을 도입하고 결정한 같은 해에 Java 1.5를 출시 한 것 같습니다 ( missed ) 열거 형에 대해 null을 지원하지 않습니다. 나중에 Java1.7 ( 20117 )에서 그들은 따랐습니다 ( 강제Don't hold your breath. Nothing resembling this is in our plans.) String과 동일한 철학 (즉, 바이트 코드를 생성하는 동안 hashcode () 메서드를 호출하기 전에 null 검사가 수행되지 않음).

따라서 enum이 처음에 들어오고 서수 시작이 0으로 구현되어 스위치 블록에서 null 값을 지원할 수 없었고 나중에 String으로 동일한 철학을 강요하기로 결정했습니다. 스위치 블록에서 허용됩니다.

TL; DR String을 사용하면 Java 코드를 바이트 코드로 변환하는 동안 NPE (null에 대한 해시 코드를 생성하려는 시도로 인해 발생)를 처리 할 수 ​​있었지만 결국 그렇게하지 않기로 결정했습니다.

참조 :
TheBUG ,
JavaVersionHistory ,
JavaCodeToByteCode ,
SO


답변

Java Docs에 따르면 :

스위치는 byte, short, char 및 int 기본 데이터 유형과 함께 작동합니다. 또한 열거 형 (Enum Types에서 설명), String 클래스, 그리고 Character, Byte, Short 및 Integer (Numbers 및 Strings에서 설명)와 같은 특정 기본 유형을 래핑하는 몇 가지 특수 클래스와 함께 작동합니다.

때문에 null어떤 유형이없고, 아무것도의 인스턴스가 아닌, 그것을 switch 문 작동하지 않습니다.


답변

대답은 단순히 참조 유형 (예 : boxed primitive 유형)과 함께 스위치를 사용하는 경우 unboxing이 NPE를 던지기 때문에 표현식이 null이면 런타임 오류가 발생한다는 것입니다.

그래서 케이스 null (불법)은 어쨌든 실행될 수 없습니다.)