Java의 새로운 switch 문

Ajisai·2024년 1월 1일
1
//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로만 했으니까 모름.. 당연함...
이래서 업데이트를 잘 봐야 하나보다.

Switch 문에 람다식 쓰기

//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에 실행할 내용을 () -> {} 형태로 쓰는 것이다.
근데이제 ()마저 생략해버린

파라미터에 Switch 문 쓰기

//Since Java 13
System.out.println(
		switch (val) {
			case 1:
				yield "One";
			case 2:
				yield "Two";
			default:
				yield "Any";
		}
);

파라미터에 쓰는 것 자체는 원래 됐던 것 같다(써본 적이 없어서 모르겠다).
다만 이걸 여기서 짚는 이유는 yield 키워드 때문.
아래에서 서술하겠지만 람다식은 쓸 수 없다.

yield가 뭐냐면

yieldswitch 문에 대한 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 키워드를 써야 한다.

break 문이 필요한가?

예전부터 가끔 하던 생각이었는데, 이번 기회에 좀 더 생각해보기로 했다.

switch (val) {
	case 1:
		System.out.println("One");
	case 2:
		System.out.println("Two");
        break;
	default:
		System.out.println("Any");

사실 break문이 필요한 경우도 있긴 하다.
실제로 겪어본 적은 없고 방금 만들어낸 것이다.

위 코드처럼 val1일 때는 두 줄에 걸쳐OneTwo를, val2일 때는 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;를 쓰는 게 일종의 옵트인같기도 하고, 여러모로 귀찮지만 이런 경우에는 오히려 좋다.
하지만 대부분의 경우 귀찮은 게 맞는 것 같다....

귀찮은데 그냥 if-else if-else 쓰면 안되나요

일반적으로 책에서 설명하는 건 다음과 같다.

  1. switch 문은 범위 지정이 안 되므로 3보다 크다와 같은 조건이 필요할 때는 if-else if-else가 낫다.
  2. 경우의 수가 많다면 if-else if-else를, 그렇지 않은 경우에는 switch 문이 낫다.

물론 중요한 내용이지만 개인적으로 속도 면의 차이점도 중요하다고 생각한다.
물론 유의미한 차이인지는 모르겠지만, 동작 방식에서 조금 차이가 있다.

Switch Vs. if-else if-else

if-else if-else의 동작 방식은

if (val == 1) {
	System.out.println("One");
} else if (val == 2) {
	System.out.println("Two");
} else {
	System.out.println("Any");
}
  1. val1인지 검사한다.
    1. 맞다면 One을 출력하고 모든 조건 검사를 종료한다.
    2. 아니라면 다음 조건 검사로 넘어간다.
  2. val2인지 검사한다.
    1. 맞다면 Two를 출력하고 모든 조건 검사를 종료한다.
    2. 아니라면 다음 조건 검사로 넘어간다.
  3. else 조건이므로 그냥 Any를 출력한다.

else를 포함해 조건이 참이 될 때까지 위에서 아래로 모든 조건을 하나씩 검사한다.

switch의 동작 방식은

switch (val) {
	case 1 -> System.out.println("One");
	case 2 -> System.out.println("Two");
	default -> System.out.println("Any");
}
  1. val 값을 확인한다.
  2. 해당되는 case의 내용을 수행한다.

더 풀어쓰면 다음과 같다.
1. val 값을 확인한다.
2. 해당되는 case의 위치로 이동하고,
3. 아래로 쭉 실행해나간다(그래서 break;가 없으면 계속 실행된다).

val 값이 case에 맞는지 하나씩 검사하는 게 아니라, 그냥 애초부터 맞는 조건의 내용만 수행하는 것이다.
if-else if-else문에 빗대어 말하자면 조건 검사는 한 번만 실행되는 셈이다.
따라서 불필요한(따지면 불필요한 건 아니지만) 조건 검사를 안 하게 된다.

물론 여러 조건(조건의 복잡성, 경우의 수 등)에 따라 유의미한 차이는 없을 수 있지만 알아두면 좋다.

정말 이렇게 동작하는지 확인하고 싶다면 OllyDbg 등의 툴로 Assembly까지 까보면 된다.
하지만 Assembly 문법도 알아야 되므로(사실 CMPJMP, JNZ 정도만 알아도 될 것 같긴 하지만) 추천하고 싶진 않다.

profile
Java를 하고 싶었지만 JavaScript를 하게 된 사람

0개의 댓글

관련 채용 정보