목차
- switch에서 문자열을 비교하는 방법
- switch의 내부 동작 원리
- switch vs if-else
- switch 사용 시 주의사항
Java 7부터는 switch문에서 문자열(String)을 비교할 수 있습니다. 기존의 if-else에서 equals()를 사용하는 방식보다 더욱 깔끔하게 문자열을 비교할 수 있습니다.
이번 글에서는 switch에서 문자열 비교 시, 내부적으로 어떻게 동작하는지 자세히 알아보겠습니다.
switch에서 문자열을 비교하는 방법
Java 7 이후에는 정수나 열거형 뿐 아니라 문자열도 switch문의 조건으로 사용할 수 있습니다. 이는 switch의 값과 case의 문자열을 String.equals 를 사용한 것처럼 비교하기 때문입니다.
The switch statement compares the String object in its expression with the expressions associated with each case label as if it were using the String.equals method
https://docs.oracle.com/javase/7/docs/technotes/guides/language/strings-switch.html
Strings in switch Statements
Strings in switch Statements In the JDK 7 release, you can use a String object in the expression of a switch statement: public String getTypeOfDayWithSwitchStatement(String dayOfWeekArg) { String typeOfDay; switch (dayOfWeekArg) { case "Monday": typeOfDay
docs.oracle.com
package pl.java.stringswitch;
public class StringSwitchExample {
public static void main(String[] args) {
String A = "Hello";
switch (A) {
case "Hello":
System.out.println("Hi!");
break;
case "Hello World":
System.out.println("Hello World");
break;
default:
System.out.println("who are you?");
}
}
}
switch의 내부 동작 원리
그렇다면 switch에서는 어떻게 문자열을 올바르게 비교할 수 있을까요?
Java 컴파일러는 if-else 구조의 String.equals 보다. switch(string) 을 더욱 효율적인 바이트 코드로 변환한다고 합니다.
The Java compiler generates generally more efficient bytecode from switch statements that use String objects than from chained if-then-else statements.
이를 확인해보기 위해 StringSwitchExample.java 을 컴파일하고, 바이트코드를 확인해보겠습니다.
1. StringSwitchExample.java 컴파일
javac 명령어로 StringSwitchExample.java를 컴파일해서 클래스 파일을 생성합니다.
javac StringSwitchExample.java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package pl.java.stringswitch;
public class StringSwitchExample {
public StringSwitchExample() {
}
public static void main(String[] var0) {
switch ("Hello") {
case "Hello" -> System.out.println("Hi!");
case "Hello World" -> System.out.println("Hello World");
default -> System.out.println("who are you?");
}
}
}
2. StringSwitchExample.class 바이트 코드 확인하기
javap 명령어로 컴파일 된 StringSwitchExample.class 의 바이트 코드를 출력합니다.
javap -c .\\StringSwitchExample.class
Compiled from "StringSwitchExample.java"
public class pl.java.stringswitch.StringSwitchExample {
public pl.java.stringswitch.StringSwitchExample();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #7 // String Hello
2: astore_1
3: aload_1
4: astore_2
5: iconst_m1
6: istore_3
7: aload_2
8: invokevirtual #9 // Method java/lang/String.hashCode:()I
11: lookupswitch { // 2
-862545276: 50
69609650: 36
default: 61
}
36: aload_2
37: ldc #7 // String Hello
39: invokevirtual #15 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_3
47: goto 61
50: aload_2
51: ldc #19 // String Hello World
53: invokevirtual #15 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_3
61: iload_3
62: lookupswitch { // 2
0: 88
1: 99
default: 110
}
88: getstatic #21 // Field java/lang/System.out:Ljava/io/PrintStream;
91: ldc #27 // String Hi!
93: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
96: goto 118
99: getstatic #21 // Field java/lang/System.out:Ljava/io/PrintStream;
102: ldc #19 // String Hello World
104: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
107: goto 118
110: getstatic #21 // Field java/lang/System.out:Ljava/io/PrintStream;
113: ldc #35 // String who are you?
115: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
118: return
}
이를 해석하면 다음과 같습니다.
- switch의 값과 모든 case의 문자열을 hashCode로 변환.
- lookupswitch를 이용해 hashCode값과 일치하는지 확인
- 일치하는 경우 String.equals 를 실행해 해쉬 충돌 방지 및 최종 검증
- caseIndex를 설정해 case 블록 선택
switch vs if-else
switch는 문자열읠 hashCode 을 빠르게 비교 후 일치하는 경우에만 String.equals 로 최종 검증을 하지만, if-else구조는 모든 조건 분기에서 String.equals 를 사용합니다.
따라서 다음과 같이 상황에 따라 적절하게 사용하면 됩니다.
- 성능이 중요하고 case가 많으면 switch
- 조건이 복잡하거나 동적인 비교가 필요하다면 if-else
switch 사용 시 주의사항
switch를 사용하기에 앞서, 올바르게 사용하지 않으면 다음과 같은 문제가 발생할 수 있습니다.
대소문자의 구분
switch로 문자열 비교시 최종적으로 String.equals를 사용하므로 대소문자를 구분해야 합니다.
consequently, the comparison of String objects in switch statements is case sensitive.
NullPointerException
switch의 값이 null일 경우 null.hashCode() 는 NPE를 발생 시킵니다.
같은 이유에서 case의 값도 null일 수 없습니다.
따라서 switch의 값에 대한 null 확인 및 case의 값에 null 비교에 주의해야 합니다.
https://github.com/rogi-rogi/tech-blog-code/tree/main/pl/java/stringswitch
'Programming Language' 카테고리의 다른 글
[Python] * 연산의 오해와 진실, 얕은/깊은 복사 (0) | 2025.01.05 |
---|---|
[Python] pip를 사용한 외장 라이브러리 삭제 (1) | 2024.12.27 |
[Java] Java의 Collection Framework에 대해 (0) | 2024.11.21 |
[Java] Double.MIN_VALUE는 음수가 아니다. (1) | 2024.11.20 |
Python 리스트 언패킹 (0) | 2024.06.19 |