[java] 삼항 연산자로 허용되지만 if 문이 아닌 정수로 null을 반환

다음 스 니펫에서 간단한 Java 코드를 살펴 보겠습니다.

public class Main {

    private int temp() {
        return true ? null : 0;
        // No compiler error - the compiler allows a return value of null
        // in a method signature that returns an int.
    }

    private int same() {
        if (true) {
            return null;
            // The same is not possible with if,
            // and causes a compile-time error - incompatible types.
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.temp());
        System.out.println(m.same());
    }
}

이 가장 간단한 Java 코드 temp()에서 함수의 리턴 유형이이지만 메소드는 컴파일러 오류를 발행하지 않으며 (문을 통해 ) int값을 리턴하려고합니다 . 컴파일되면 런타임 예외가 발생 합니다.nullreturn true ? null : 0;NullPointerException

그러나 if( same()메소드 에서 와 같이) 명령문으로 삼항 연산자를 나타내면 컴파일 타임 오류 발생하는 경우에도 같은 문제가 발생합니다! 왜?



답변

컴파일러는 null에 대한 null 참조로 해석 Integer하고 조건부 연산자 ( Java Language Specification, 15.25에 설명 된대로)에 대한 오토 박싱 / 언 박싱 규칙을 적용하고 행복하게 진행합니다. NullPointerException런타임시 이를 생성하여 시도하여 확인할 수 있습니다.


답변

Java 컴파일러 true ? null : 0Integer표현식으로 해석 되며 암시 적으로로 변환 int하여을 제공 할 수 있다고 생각합니다 NullPointerException.

두 번째 경우를 들어, 표현은 null특별하다 널 유형 참조 코드가 있으므로, return null형식이 일치한다.


답변

실제로, 그 모든 것은 Java 언어 사양에 설명되어 있습니다.

조건식의 유형은 다음과 같이 결정됩니다.

  • 두 번째 및 세 번째 피연산자가 동일한 유형 (널 유형일 수 있음)을 갖는 경우 이는 조건식의 유형입니다.

따라서 귀하의 “null” (true ? null : 0)은 int 유형을 얻은 다음 정수로 자동 박스됩니다.

이것을 확인하기 위해 이와 같은 것을 시도 (true ? null : null)하면 컴파일러 오류가 발생합니다.


답변

if명령문 의 경우 null참조는 Integer참조 로 해석되도록 하는 표현식에 참여하지 않으므로 참조 로 취급 되지 않습니다 . 따라서 오류가 더 명확하게 유형 오류 이므로 컴파일 타임에 오류가 쉽게 잡힐 수 있습니다 .

조건부 연산자와 관련하여 Java 언어 사양 §15.25“조건부 연산자 ? :”는 유형 변환이 적용되는 규칙에 따라 다음과 같이 잘 응답합니다.

  • 두 번째 및 세 번째 피연산자가 동일한 유형 (널 유형일 수 있음)을 갖는 경우 이는 조건식의 유형입니다.

    이 없기 때문에 적용 null되지 않습니다 int.


  • 두 번째 및 세 번째 피연산자 중 하나가 부울 유형이고 다른 유형의 부울이 유형이 부울 인 경우 조건식의 유형은 부울입니다.

    어느 쪽도 있기 때문에 적용되지 않음 nullint없다 booleanBoolean.


  • 두 번째 및 세 번째 피연산자 중 하나가 널 유형이고 다른 유형의 유형이 참조 유형 인 경우 조건식의 유형은 해당 참조 유형입니다. 널 유형

    이므로 적용 되지 않지만 참조 유형은 아닙니다.nullint


  • 그렇지 않으면 두 번째 및 세 번째 피연산자에 숫자 유형으로 변환 가능한 유형 (§5.1.8)이있는 경우 몇 가지 경우가 있습니다. […]

    적용 : null숫자 유형으로 변환 가능한 것으로 취급되며 §5.1에 정의되어 있습니다. 8“Unboxing Conversion”을 던지십시오 NullPointerException.


답변

가장 먼저 염두에 두어야 할 것은 Java 3 진 연산자에는 “유형”이 있으며 이는 두 번째 또는 세 번째 매개 변수의 실제 / 실제 유형에 관계없이 컴파일러가 결정하고 고려하는 것입니다. 몇 가지 요인에 따라 삼항 연산자 유형은 Java 언어 사양 15.26에 설명 된대로 다른 방식으로 결정됩니다.

위의 질문에서 우리는 마지막 경우를 고려해야합니다.

그렇지 않으면, 두 번째 및 세 번째 피연산자는 각각 S1S2 유형 입니다. 하자 T1이 에 권투 변환을 적용 결과 그 유형이 될 S1 및하자가 T2 타입이 될 그에게 권투 변환을 적용 결과 S2 . 조건식의 유형은 캡처 변환 (§5.1.10)을 lub (T1, T2) (§15.12.2.7) 에 적용한 결과입니다 .

캡처 변환 (§5.1.10) 적용을 살펴보면 가장 복잡한 경우 입니다. lub (T1, T2)입니다.

평범한 영어로 그리고 극단적으로 단순화 한 후에 프로세스는 두 번째 및 세 번째 매개 변수의 “최소 공통 수퍼 클래스”(예, LCM 생각)를 계산하는 것으로 설명 할 수 있습니다. 이것은 삼항 연산자 “type”을 줄 것입니다. 다시 말하지만 방금 말한 것은 극단적 인 단순화입니다 (여러 공통 인터페이스를 구현하는 클래스 고려).

예를 들어 다음을 시도하면

long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));

조건식의 결과 유형은 /에 java.util.Date대한 “최소 공통 수퍼 클래스”이므로TimestampTime 쌍 .

null무엇이든 오토 박스 할 수 있기 때문에 “최소 공통 수퍼 클래스”는Integer 클래스이며 위의 조건식 (삼항 연산자)의 반환 유형이됩니다. 리턴 값은 유형의 널 포인터가 Integer되고 이는 삼항 연산자에 의해 리턴됩니다.

런타임에 Java Virtual Machine이 개봉하면 Integera NullPointerException가 발생합니다. JVM이 함수를 호출하려고하기 때문에 발생합니다 null.intValue().null autoboxing의 결과입니다.

내 의견으로는 (그리고 내 의견은 Java 언어 사양에 없기 때문에 많은 사람들이 어쨌든 잘못 알 것입니다) 컴파일러는 귀하의 질문에 표현을 평가하는 데 열악한 일을합니다. true ? param1 : param2컴파일러가 작성한 것을 고려 하면 첫 번째 매개 변수– null가 반환되고 컴파일러 오류가 발생 하는지 즉시 결정 해야합니다. 이것은 작성시 while(true){} etc...와 다소 유사 하며 컴파일러는 루프 아래의 코드에 대해 불평하고로 플래그를 지정합니다 Unreachable Statements.

두 번째 경우는 매우 간단 하며이 답변은 이미 너무 깁니다 …;)

보정:

다른 분석 후 나는 null가치가 무엇이든 박스 / 오토 박스 될 수 있다고 말하는 것이 잘못되었다고 생각합니다 . 클래스 Integer에 대해 말하면, 명시 적 권투는 new Integer(...)생성자 또는 Integer.valueOf(int i);(어딘가 에서이 버전을 찾았 습니다)를 호출하는 것으로 구성 됩니다. 전자는 NumberFormatException(그리고 이것이 일어나지 않습니다) 던지는 반면 두 번째는 불가능하기 때문에 의미 int가 없습니다 null


답변

실제로 첫 번째 경우에는 컴파일러가 알고 있으므로 식을 평가할 수 Integer있지만 두 번째 경우에는 반환 값 ( null) 의 유형을 결정할 수 없으므로 컴파일 할 수 없습니다. 로 캐스팅 Integer하면 코드가 컴파일됩니다.


답변

private int temp() {

    if (true) {
        Integer x = null;
        return x;// since that is fine because of unboxing then the returned value could be null
        //in other words I can say x could be null or new Integer(intValue) or a intValue
    }

    return (true ? null : 0);  //this will be prefectly legal null would be refrence to Integer. The concept is one the returned
    //value can be Integer 
    // then null is accepted to be a variable (-refrence variable-) of Integer
}