Java 스위치 내에서 변수 선언 및 초기화


99

Java 스위치에 대해 미친 질문이 있습니다.

int key = 2;

switch (key) {
    case 1:
        int value = 1;
        break;
    case 2:
        value = 2;
        System.out.println(value);
        break;
    default:
        break;
}

시나리오 1- key값이 2이면 성공적으로 값을 2로 인쇄합니다.
시나리오 2-주석 value = 2case 2:달면 The local variable value may be initialized .

질문 :

시나리오 1 : 실행 흐름이 이동하지 않는 경우 case 1:합니다 (시 key = 2), 다음 어떻게 같은 값 변수의 유형을 알 수 있습니까 int?

시나리오 2 : 컴파일러가 값 변수의 유형을으로 알고 있으면 . (선언 및 초기화) intint value = 1;표현식에 액세스해야합니다 case 1:. 그럼 왜 그것이 내가 언급을하겠습니다 때 sqawrk 수행 value = 2case 2:속담, 초기화되지 않았을 수 지역 변수의 값을 .


13
미친 질문이 아니라 아주 좋은 질문입니다.
biziclop


@PhilippeCarriere 사실, 나는 그것이 역으로 있어야한다고 생각합니다 .JLS에 대한 직접적인 참조가 있기 때문에 여기에 대한 대답이 더 좋습니다 (게시물이 더 최신 인 경우에도), 해당 게시물의 다른 답변에서 다루는 문제를 잘 요약합니다. 을 (를) 참조하십시오 .
Tunaki

@Tunaki 중복에 대한 설명은 "이 질문은 이전에 요청되었습니다"로 시작합니다. 나는 나중의 것이 이전의 복제물로 표시되어야한다는 것을 읽고 있습니다. 그러나 나는 이것이 좋은 요소를 가지고 있다는 데 동의합니다. 어떻게 든 병합해야할까요?
Philippe Carriere

또한 SO에 대한 많은 질문이 내 원래 질문의 중복으로 표시 되므로이 질문을 새 원본으로 표시하는 것이 더 낫다고 결정하면 모든 링크를 수정하여 내 대신이 질문을 참조하십시오.
Philippe Carriere

답변:


114

Switch 문은 기본적으로 범위 지정 측면에서 이상합니다. 에서 JLS의 섹션 6.3 :

블록 (§14.4)에서 지역 변수 선언의 범위는 선언이 나타나는 나머지 블록으로, 자체 이니셜 라이저로 시작하고 지역 변수 선언문의 오른쪽에있는 추가 선언자를 포함합니다.

귀하의 경우, case 2는 실행되지 않더라도 동일한 블록에 있으며 case 1그 뒤에 나타납니다 case 1. 따라서 논리적으로 선언을 "실행"하지 않더라도 지역 변수가 범위 내에 있고 수 있습니다 . (초기화가 가능하지만 선언은 실제로 "실행 가능"하지 않습니다.)

주석 처리하면 value = 2;할당 하면 컴파일러는 여전히 참조하는 변수를 알고 있지만 값을 할당하는 실행 경로를 거치지 않았기 때문에 시도 할 때와 같은 오류가 발생합니다. 명확하게 할당되지 않은 다른 지역 변수를 읽습니다.

다른 경우에 선언 된 지역 변수를 사용 하지 않는 것이 좋습니다 . 지금까지 본 것처럼 코드를 매우 혼란스럽게 만듭니다. switch 문에 지역 변수를 도입 할 때 (드물게 시도하는 경우-사례가 매우 짧아야합니다. 이상적으로는) 일반적으로 새로운 범위를 도입하는 것을 선호합니다.

case 1: {
    int value = 1;
    ...
    break;
}
case 2: {
    int value = 2;
    ...
    break;
}

나는 이것이 더 명확하다고 믿습니다.


11
+1은 "초기화가 가능하지만 선언은 실제로"실행 가능 "하지 않습니다." 그리고 Skeet의 조언에 감사드립니다.
namalfernandolk

1
JEP-325가 통합됨에 따라 지역 변수의 범위 그림이 변경 되었으며 스위치 블록 대신 케이스간에 동일한 이름을 사용할 수 있습니다. 유사한 블록 코딩에도 의존하지만. 또한 스위치 케이스 별 변수에 할당 된 값은 스위치 표현식을 사용하면 훨씬 편리합니다.
Naman

중괄호로 새 범위를 추가하기위한 포인트입니다. 당신이 그렇게 할 수 있는지조차 몰랐습니다.
Floating Sunfish

21

변수가 선언되었지만 (int로) 초기화되지 않았습니다 (초기 값이 할당 됨). 라인을 생각해보십시오.

int value = 1;

같이:

int value;
value = 1;

int value부분은 컴파일 타임에 int 인 value라는 변수가 있음을 컴파일러에 알립니다. value = 1부분을 초기화하지만 실행 시간에 발생, 스위치의 해당 분기를 입력하지 않으면 전혀 발생하지 않습니다.


컴파일 타임과 런타임의 선언과 초기화에 대한 멋진 설명은 +1입니다.
namalfernandolk

18

에서 http://www.coderanch.com/t/447381/java-programmer-SCJP/certification/variable-initialization-within-case-block

선언은 컴파일 타임에 처리되며 코드의 실행 흐름에 의존하지 않습니다. value스위치 블록의 로컬 범위 내에서 선언 되기 때문에 선언 지점부터 해당 블록의 모든 위치에서 사용할 수 있습니다.


1
이 답변이 찬성되는 이유는 무엇입니까? 그것은 질문에 대답하지 않는 폴 또는 스키트의 대답은 ... 달리
두식 Gairola

7
그렇습니다. 그래서, +1, 1 페니, 내 쪽에서도.
Ravinder Reddy

3

JEP 325 : JDK-12 얼리 액세스 빌드의 Switch Expressions (미리보기) 통합으로 . 에서 볼 수있는 특정 변화가 존의 대답은 -

  1. 로컬 변수 범위 -스위치 케이스의 로컬 변수는 이제 전체 스위치 블록 대신 케이스 자체에 로컬이 될 수 있습니다. Day추가 설명을 위해 enum 클래스를고려한 예 (Jon이 구문 론적으로 시도한 것과 유사):

    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    // some another method implementation
    Day day = Day.valueOf(scanner.next());
    switch (day) {
        case MONDAY,TUESDAY -> {
            var temp = "mon-tue";
            System.out.println(temp);
        }
        case WEDNESDAY,THURSDAY -> {
            var temp = Date.from(Instant.now()); // same variable name 'temp'
            System.out.println(temp);
        }
        default ->{
            var temp = 0.04; // different types as well (not mandatory ofcourse)
            System.out.println(temp);
        }
    }
  2. Switch Expressions- 의도가 변수에 값을 할당 한 다음 사용하려는 경우 스위치 표현식을 사용할 수 있습니다. 예 :

    private static void useSwitchExpression() {
        int key = 2;
        int value = switch (key) {
            case 1 ->  1;
            case 2 -> 2;
            default -> {break 0;}
        };
        System.out.println("value = " + value); // prints 'value = 2'
    }

0

이 설명이 도움이 될 수 있습니다.

    int id=1;

    switch(id){
        default: 
            boolean b= false; // all switch scope going down, because there is no scope tag

        case 1:
            b = false;
        case 2:{
            //String b= "test"; you can't declare scope here. because it's in the scope @top
            b=true; // b is still accessible
        }
        case 3:{
            boolean c= true; // case c scope only
            b=true; // case 3 scope is whole switch
        }
        case 4:{
            boolean c= false; // case 4 scope only
        }
    }

0

자바 사양 :

https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.11

레이블이있는 중단으로 인한 갑작스러운 완료의 경우 레이블이있는 문에 대한 일반 규칙 (§14.7)에 의해 처리됩니다.

https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.7

라벨이있는 진술 :

LabeledStatement : 식별자 : 문

LabeledStatementNoShortIf : 식별자 : StatementNoShortIf

C 및 C ++와 달리 Java 프로그래밍 언어에는 goto 문이 없습니다. 식별자 문 레이블은 레이블이있는 문 내 어디에서나 나타나는 break (§14.15) 또는 continue (§14.16) 문과 함께 사용됩니다.

레이블이있는 명령문의 레이블 범위는 즉시 포함 된 명령문입니다.

즉, case 1, case 2는 switch 문 내의 레이블입니다. break 및 continue 문을 레이블에 적용 할 수 있습니다.

레이블은 문의 범위를 공유하므로 레이블 내에 정의 된 모든 변수는 switch 문의 범위를 공유합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.