JEP 354: Switch Expressions (Preview)

JEP 354: Switch Expressions (Preview)

Summary

s확장 switch하여 명령문 또는 표현식으로 사용할 수 있도록하여 두 형식 모두 기존
case … :레이블 (전파 포함) 또는 새 case … ->레이블 (전파 없음)을 사용하고, 새 레이블을 사용하여 값을 산출합니다.
switch표현. 이러한 변화는 코딩 일상을 단순화하고, 사용을위한 방법을 준비 패턴 매칭 (JEP 305) 에서 switch. 이것은 JDK 13 의 미리보기 언어 기능 입니다.

History

스위치 표현은 2017 년 12 월 JEP 325에 의해 제안되었습니다. 그들은 2019 년 8 월 JDK (12)을 대상으로 A와 미리보기 기능 배포 했다.
처음에는 피처의 디자인과 switch표현식 사용 경험 및 개선 된 switch문장 에 대한 피드백을 찾았습니다.
이 피드백을 기반으로이 JEP는 기능을 한 번 변경합니다.

switch 표현식 에서 값을 산출하기 위해 break with value 문은 명령문을 yield 위해 삭제됩니다.

Motivation

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

현재 Java switch문장 의 설계는 C 및 C ++와 같은 언어를 따르며 기본적으로 시맨틱 스를 지원합니다.
이 전통적인 제어 흐름은 switch높은 수준의 컨텍스트에서 사용되는 낮은 수준의 코드 (예 : 이진 인코딩 파서)를 작성하는 데 유용 하지만
오류가 발생하기 쉬운 특성이 유연성을 능가하기 시작합니다. 예를 들어, 다음 코드에서 많은 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, yield, return과 continue, 스루 점프 할 수없는 switch등 다음과 같이 표현 :

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

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

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

Dependencies

이 기능은 JEP 325 에서 미리보기되었습니다 .

패턴 일치 (JEP 305) 는이 JEP에 따라 다릅니다.

Risks and Assumptions

레이블이 있는 switch진술 의 필요성 case L ->이 불분명 한 경우가 있습니다. 다음의 이론적 근거는 포함에 대한 가정을 제시한다.

  • switch부작용으로 운영하지만, 일반적으로 여전히 “라벨 당 하나 개의 행동” 문 있습니다.
    새로운 스타일의 레이블을 사용하여 접을 수있게하면 문장이보다 간단하고 오류 발생이 줄어 듭니다.

  • switch명령문 블록 의 기본 제어 플로우가 발생 하지 않고 넘어 간다는 사실은 Java 역사 초기에 불행한 선택이었습니다.
    개발자에게는 큰 문제입니다. 이것은 표현 switch뿐만 아니라 일반적으로 구문에 대해 해결해야 할 것으로 보입니다 switch.

  • 원하는 이점 (표현성, 더 나은 제어 흐름, 더 정확한 범위 지정)을 직교 특징으로 애타게 표현하는 것이 더 바람직해 보였으므로
    switch표현과 표현 switch이 더 공통적 일 수있었습니다. switch표현과 표현 의 차이가 클수록 switch언어를 배우는 것이 더 복잡해지고
    개발자가 스스로 이해하기가 더 예리합니다.

참조