//Since Java 12
switch (val) {
case 1 -> System.out.println("One");
case 2 -> System.out.println("Two");
default -> System.out.println("Any");
}
//Since Java 13
System.out.println(
switch (val) {
case 1:
yield "one";
case 2:
yield "two";
default:
yield "Any";
}
);
IntelliJ에서 이것저것 설정을 하다가 신기한 문법이 보였다.
아니 이런 게 있었다고?? 싶어서 알아보니 Java 12, 13부터 추가되었다고 한다.
문법 공부를 Java 8로만 했으니까 모름.. 당연함...
이래서 업데이트를 잘 봐야 하나보다.
//Since Java 12
switch (val) {
case 1 -> System.out.println("One");
case 2 -> System.out.println("Two");
default -> System.out.println("Any");
}
Java 12에 추가된 문법으로, ->
는 Lambda expression의 그것이다.
그러니까 case 1
에 실행할 내용을 () -> {}
형태로 쓰는 것이다.
근데이제 ()
마저 생략해버린
//Since Java 13
System.out.println(
switch (val) {
case 1:
yield "One";
case 2:
yield "Two";
default:
yield "Any";
}
);
파라미터에 쓰는 것 자체는 원래 됐던 것 같다(써본 적이 없어서 모르겠다).
다만 이걸 여기서 짚는 이유는 yield
키워드 때문.
아래에서 서술하겠지만 람다식은 쓸 수 없다.
yield
가 뭐냐면yield
는 switch
문에 대한 return
정도로 보면 된다.
그래서 쓰는 법도 return
과 같다.
즉 yield {{CONDITION}} ? {{WHEN_TRUE}} : {{WHEN_FALSE}};
나, yield method();
도 된다.
int val = (int)(Math.random() * 10)) - 1
System.out.println(
switch ((int)(Math.random() * 10)) - 1) { //이건 안되고
switch (val) { //이건 된다.
case 1:
yield "One";
case 2:
yield "Two";
default:
yield "Any";
}
);
System.out.println(switch (val) {
case 1 -> System.out.println("One");
case 2 -> System.out.println("Two");
default -> System.out.println("Any");
});
이건 불가능하다.
앞의 예제처럼 yield
키워드를 써야 한다.
예전부터 가끔 하던 생각이었는데, 이번 기회에 좀 더 생각해보기로 했다.
switch (val) {
case 1:
System.out.println("One");
case 2:
System.out.println("Two");
break;
default:
System.out.println("Any");
사실 break
문이 필요한 경우도 있긴 하다.
실제로 겪어본 적은 없고 방금 만들어낸 것이다.
위 코드처럼 val
이 1
일 때는 두 줄에 걸쳐One
과 Two
를, val
이 2
일 때는 Two
만 출력하고 싶다면 필요하다.
이런 경우가 실제로 많을까? 는 다른 문제니 일단 차치한다.
우선 break
문 없이 쓸 수 있을지 고민해봤는데, 당연히 가능은 하다.
switch (val) {
case 1 -> {
System.out.println("One");
System.out.println("Two");
}
case 2 -> System.out.println("Two");
default -> System.out.println("Any");
}
하지만 기껏 없앤 중복 코드를 다시 써야 하고, 유지보수 면에서도 썩 좋지 않다.
Two
대신 two
를 출력하고 싶어졌다면 원래 한 군데 바꿀 걸 두 군데를 수정해야 하니 말이다.
그래서 break;
를 쓰는 게 일종의 옵트인같기도 하고, 여러모로 귀찮지만 이런 경우에는 오히려 좋다.
하지만 대부분의 경우 귀찮은 게 맞는 것 같다....
일반적으로 책에서 설명하는 건 다음과 같다.
switch
문은 범위 지정이 안 되므로 3보다 크다와 같은 조건이 필요할 때는if-else if-else
가 낫다.- 경우의 수가 많다면
if-else if-else
를, 그렇지 않은 경우에는switch
문이 낫다.
물론 중요한 내용이지만 개인적으로 속도 면의 차이점도 중요하다고 생각한다.
물론 유의미한 차이인지는 모르겠지만, 동작 방식에서 조금 차이가 있다.
if-else if-else
의 동작 방식은if (val == 1) {
System.out.println("One");
} else if (val == 2) {
System.out.println("Two");
} else {
System.out.println("Any");
}
val
이 1
인지 검사한다.One
을 출력하고 모든 조건 검사를 종료한다.val
이 2
인지 검사한다.Two
를 출력하고 모든 조건 검사를 종료한다.else
조건이므로 그냥 Any
를 출력한다.즉 else
를 포함해 조건이 참이 될 때까지 위에서 아래로 모든 조건을 하나씩 검사한다.
switch
의 동작 방식은switch (val) {
case 1 -> System.out.println("One");
case 2 -> System.out.println("Two");
default -> System.out.println("Any");
}
val
값을 확인한다.case
의 내용을 수행한다.더 풀어쓰면 다음과 같다.
1. val
값을 확인한다.
2. 해당되는 case
의 위치로 이동하고,
3. 아래로 쭉 실행해나간다(그래서 break;
가 없으면 계속 실행된다).
즉 val
값이 case
에 맞는지 하나씩 검사하는 게 아니라, 그냥 애초부터 맞는 조건의 내용만 수행하는 것이다.
if-else if-else
문에 빗대어 말하자면 조건 검사는 한 번만 실행되는 셈이다.
따라서 불필요한(따지면 불필요한 건 아니지만) 조건 검사를 안 하게 된다.
물론 여러 조건(조건의 복잡성, 경우의 수 등)에 따라 유의미한 차이는 없을 수 있지만 알아두면 좋다.
정말 이렇게 동작하는지 확인하고 싶다면 OllyDbg 등의 툴로 Assembly까지 까보면 된다.
하지만 Assembly 문법도 알아야 되므로(사실 CMP
와 JMP
, JNZ
정도만 알아도 될 것 같긴 하지만) 추천하고 싶진 않다.