JEP 325: Switch Expressions (Preview)

JEP 325: Switch Expressions (Preview)

Summary

switch명령문을 명령문 또는 표현식으로 사용할 수 있도록 확장하고 두 양식 모두 “전통적인”또는 “단순화 된”
범위 지정 및 제어 플로우 동작을 사용할 수 있도록 명령문을 확장하십시오.
이러한 패턴 매칭 (JEP 305) 에서 switch 변화는 일상 코딩 단순화함.
이것은 JDK 12 의 미리보기 언어 기능 입니다.

참고 :이 JEP는 JDK 13을 대체하는 JEP 354 로 대체되었습니다

Motivation

패턴 일치 (JEP 305) 를 지원하기 위해 Java 프로그래밍 언어를 향상시킬 준비를 할 때 기존 switch문장 의 몇 가지 불규칙성
( 오랫동안 사용자에게 자극을 주었던)이 장애가됩니다. 여기에는 스위치 블록의 기본 제어 흐름 동작 (통과),
스위치 블록의 기본 범위 지정 (블록이 하나의 단일 범위로 처리됨) switch이 포함되며 일반적으로 다중을 표현하는 것이
더 자연 스럽지만 명령문으로 만 작동합니다. 조건식을 표현식으로 사용합니다.

현재 Java switch 문장 의 설계는 C 및 C ++와 같은 언어를 따르며 기본적으로 대체 의미를 지원합니다.
이 전통적인 제어 흐름은 저수준 코드 (이진 인코딩 용 파서와 같은)를 작성하는 데 유용하지만
스위치는 높은 수준의 컨텍스트에서 사용되므로 오류가 발생하기 쉬운 특성이 유연성을 능가하기 시작합니다.

예를 들어, 다음 코드에서 많은 break 명령문은 불필요하게 장황하게 만들며,이 시각적 노이즈는 종종 오류를 디버그하기 어렵게합니다.
누락 된 break 명령문은 우발적 인 폴스 루가 발생 함을 의미합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}


case L ->레이블이 일치하면 레이블 오른쪽에있는 코드 만 실행됨을 나타 내기 위해 “ “로 작성된 새로운 형식의 스위치 레이블을 도입 할 것을 제안합니다 .
예를 들어, 이전 코드를 작성할 수 있습니다.

1
2
3
4
5
6
7
8

switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}

(이 예제에서는 여러 사례 레이블도 사용합니다. 단일 스위치 레이블에서 여러 개의 쉼표로 구분 된 레이블을 지원할 것을 제안합니다.)

“ case L ->”스위치 레이블 의 오른쪽에있는 코드 는 표현식, 블록 또는 (편의를 위해) throw명령문으로 제한됩니다.
이는 아암이 로컬 변수를 도입해야하는 즐거운 결과를 가져 오며, 이는 블록에 포함되어야하고 따라서 스위치 블록의 다른
아암에 대한 범위가 아니어야합니다. 이것은 로컬 변수의 범위가 전체 스위치 블록 인 “전통적인”스위치 블록으로 인한 또 다른 성가심을 제거합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

switch (day) {
case MONDAY:
case TUESDAY:
int temp = ...
break;
case WEDNESDAY:
case THURSDAY:
int temp2 = ... // Why can't I call this temp?
break;
default:
int temp3 = ... // Why can't I call this temp?
}

기존의 많은 switch명령문은 본질적으로 switch표현식의 시뮬레이션으로 , 각 팔은 공통 대상 변수에 지정하거나 값을 반환합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
case THURSDAY:
case SATURDAY:
numLetters = 8;
break;
case WEDNESDAY:
numLetters = 9;
break;
default:
throw new IllegalStateException("Wat: " + day);
}


이것을 진술로 표현하는 것은 우회적이며 반복적이며 오류가 발생하기 쉽습니다.
저자는 numLetters매일 의 가치를 계산해야한다고 표현했습니다.
보다 명확하고 안전한 switch expression을 사용하여 직접 말할 수 있어야합니다 .

1
2
3
4
5
6
7
8

int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};

결과적으로 switch표현식을 지원하도록 확장 하면 흐름 분석 확장
(표현식이 항상 값을 계산하거나 갑자기 완료해야 함)과 같은 일부 추가 요구 사항이 발생하고
표현식의 일부 사례 switch가 값을 산출하지 않고 예외를 처리 할 수 있습니다.

Description

“전통적인”스위치 블록 외에도 새로운 “ case L ->”스위치 레이블이 있는 새로운 “단순화 된”양식을 추가 할 것을 제안합니다.
레이블이 일치하면 화살표 레이블 오른쪽의 표현식 또는 명령문 만 실행됩니다. 넘어지지 않습니다. 예를 들어 다음과 같은 방법이 있습니다.

1
2
3
4
5
6
7
8
9

static void howMany(int k) {
switch (k) {
case 1 -> System.out.println("one");
case 2 -> System.out.println("two");
case 3 -> System.out.println("many");
}
}

다음코드 :

1
2
3
4
5

howMany(1);
howMany(2);
howMany(3);

결과

1
2
3
4
one
two
many

switch추가로 표현식으로 사용할 수 있도록 명령문 을 확장합니다 . 일반적인 경우 switch식은 다음과 같습니다.

1
2
3
4
5
6
7

T result = switch (arg) {
case L1 -> e1;
case L2 -> e2;
default -> e3;
};

switch식은 폴리 표현이다; 대상 유형이 알려진 경우이 유형은 각 팔로 아래로 밀립니다.
switch식 의 유형은 알려진 경우 대상 유형입니다. 그렇지 않은 경우 독립형 유형은 각 케이스 암의 유형을 결합하여 계산됩니다.

대부분의 switch표현식에는 “ case L ->”스위치 레이블 오른쪽에 단일 표현식이 있습니다.
전체 블록이 필요한 경우, 우리는 break명령문을 확장하여 인수를 가져 오며, 이는 둘러싸는 switch표현식 의 값이됩니다 .

1
2
3
4
5
6
7
8
9
10
11

int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int k = day.toString().length();
int result = f(k);
break result;
}
};

switch표현은 같은 수 있습니다 switch성명도 “와”전통 “스위치 블록을 사용하여 case L:”전환 라벨 (의미 가을-을 통해 의미).
이 경우 break with value 문을 사용하여 값을 산출 합니다.

1
2
3
4
5
6
7
8
9
10
11

int result = switch (s) {
case "Foo":
break 1;
case "Bar":
break 2;
default:
System.out.println("Neither Foo nor Bar, hmmm...");
break 0;
};

두 가지 형태 break(가치가 있거나없는)는 두 가지 형태의 return방법 과 유사 합니다.
두 가지 형태 모두 return메소드 실행을 즉시 종료합니다. 비 공백 메소드에서는 메소드의 호출자에게 제공되는 값을 추가로 제공해야합니다.
( break표현식 값과 break레이블 형식 간의 모호성은 비교적 쉽게 처리 할 수 ​​있습니다.)

switch표현 의 경우 철저해야합니다. 가능한 모든 값에 대해 일치하는 스위치 레이블이 있어야합니다.
실제로 이것은 일반적으로 default절이 필요 하다는 것을 의미 합니다.
그러나 enum switch알려진 모든 사례를 포함 하는 표현식 (및 궁극적으로 switch봉인 된 유형에 대한 표현식)의 경우,
컴파일 시간과 런타임 사이에 정의가 변경 default되었음을 나타내는 절을 컴파일러에서 삽입 할 수 있습니다 enum.
(이것은 오늘날 개발자가 직접 수행하는 작업이지만 컴파일러를 삽입하면 수동으로 작성하는 것보다 덜 방해적이고
더 설명적인 오류 메시지가 나타날 수 있습니다.)

또한 switch표현식은 정상적으로 값 또는 throw예외로 완료되어야합니다.
이것은 많은 결과를 초래합니다. 먼저, 컴파일러는 모든 스위치 레이블에 대해 일치하는지 확인한 후 값을 얻을 수 있는지 확인합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

int i = switch (day) {
case MONDAY -> {
System.out.println("Monday");
// ERROR! Block doesn't contain a break with value
}
default -> 1;
};
i = switch (day) {
case MONDAY, TUESDAY, WEDNESDAY:
break 0;
default:
System.out.println("Second half of the week");
// ERROR! Group doesn't contain a break with value
};

또 다른 결과는 그 제어 문 break, return및 continue, 스루 점프 할 수없는 switch등 다음과 같이 표현 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

z:
for (int i = 0; i < MAX_VALUE; ++i) {
int k = switch (e) {
case 0:
break 1;
case 1:
break 2;
default:
continue z;
// ERROR! Illegal jump through a switch expression
};
...
}

기회의 목표로 플로트, 더블 및 롱과 같이 이전에 허용되지 않은 기본 유형 (및 해당 상자 유형)의 전환을 지원하도록 스위치를 확장 할 수 있습니다.

Dependencies

Pattern Matching (JEP 305)

참조