본문 바로가기
자바

[Java] if-else vs switch, 조건문의 속도 차이와 그 이유

by 책 읽는 개발자_테드 2021. 12. 5.
반응형

다음과 같이 같은 기능을 하는 switch문과 if문을 작성해보자.

 

public class SwitchAndIf {
   public static void switchTest(int num) {
      switch (num) {
         case 1:
            System.out.println("숫자 1입니다.");
            break;
         case 2:
            System.out.println("숫자 2입니다.");
            break;
         case 3:
            System.out.println("숫자 3입니다.");
            break;
         case 4:
            System.out.println("숫자 4입니다.");
            break;
         case 5:
            System.out.println("숫자 5입니다.");
            break;
         default:
            System.out.println("알 수 없는 숫자입니다.");
      }
   }

   public static void IfTest(int num) {
      if (num == 1) {
         System.out.println("숫자 1입니다.");
      } else if (num == 2) {
         System.out.println("숫자 2입니다.");
      } else if (num == 3) {
         System.out.println("숫자 3입니다.");
      } else if (num == 4) {
         System.out.println("숫자 4입니다.");
      } else if (num == 5) {
         System.out.println("숫자 5입니다.");
      } else {
         System.out.println("알 수 없는 숫자입니다.");
      }
   }
}

 

그리고 두 함수의 바이트코드를 비교해보자. 먼저 if문의 바이트코드를 살펴보자.

 

  public static IfTest(I)V
   L0
    LINENUMBER 25 L0
    ILOAD 0
    ICONST_1
    IF_ICMPNE L1
   L2
    LINENUMBER 26 L2
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 1\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    GOTO L3
   L1
    LINENUMBER 27 L1
   FRAME SAME
    ILOAD 0
    ICONST_2
    IF_ICMPNE L4
   L5
    LINENUMBER 28 L5
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 2\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    GOTO L3
   L4
    LINENUMBER 29 L4
   FRAME SAME
    ILOAD 0
    ICONST_3
    IF_ICMPNE L6
   L7
    LINENUMBER 30 L7
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 3\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    GOTO L3
   L6
    LINENUMBER 31 L6
   FRAME SAME
    ILOAD 0
    ICONST_4
    IF_ICMPNE L8
   L9
    LINENUMBER 32 L9
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 4\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    GOTO L3
   L8
    LINENUMBER 33 L8
   FRAME SAME
    ILOAD 0
    ICONST_5
    IF_ICMPNE L10
   L11
    LINENUMBER 34 L11
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 5\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
    GOTO L3
   L10
    LINENUMBER 36 L10
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc54c \uc218 \uc5c6\ub294 \uc22b\uc790\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L3
    LINENUMBER 38 L3
   FRAME SAME
    RETURN
   L12
    LOCALVARIABLE num I L0 L12 0
    MAXSTACK = 2
    MAXLOCALS = 1

 

위 코드를 보면  if문을 각각의 조건을 IF_ICMPNE (If Integer Compare Not Equal) 명령어로 값을 비교한다. 때문에 아래 그림처럼 조건이 많아 질수록 연산량이 늘어난다.

 

 

이번에는 switch문의 바이트코드를 살펴보자. 

 

public static switchTest(I)V
   L0
    LINENUMBER 3 L0
    ILOAD 0
    TABLESWITCH
      1: L1
      2: L2
      3: L3
      4: L4
      5: L5
      default: L6
   L1
    LINENUMBER 5 L1
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 1\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L7
    LINENUMBER 6 L7
    GOTO L8
   L2
    LINENUMBER 8 L2
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 2\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L9
    LINENUMBER 9 L9
    GOTO L8
   L3
    LINENUMBER 11 L3
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 3\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L10
    LINENUMBER 12 L10
    GOTO L8
   L4
    LINENUMBER 14 L4
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 4\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L11
    LINENUMBER 15 L11
    GOTO L8
   L5
    LINENUMBER 17 L5
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc22b\uc790 5\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L12
    LINENUMBER 18 L12
    GOTO L8
   L6
    LINENUMBER 20 L6
   FRAME SAME
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "\uc54c \uc218 \uc5c6\ub294 \uc22b\uc790\uc785\ub2c8\ub2e4."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L8
    LINENUMBER 22 L8
   FRAME SAME
    RETURN
   L13
    LOCALVARIABLE num I L0 L13 0
    MAXSTACK = 2
    MAXLOCALS = 1

 

코드의 앞 부분을 보면 TABLESWITCH가 생성된다. 이것은 점프 테이블(분기 테이블)로 특정 조건의 데이터가 입력되면 프로그램의 제어를 프로그램의 다른 부분으로 옮기게된다. 이러한 방식의 차이로 일반적으로 switch문이 if-else 문 보다 빠를 수 있다.

 

실제론

 

실제로는 다음과 같은 이유로 이론과 다를 수 있다. 

1. 대부분의 경우 처음 if문에서 처리되고, 아주 일부만 else에서 처리되는 경우가 있을 수 있다.

2. CPU의 분기 예측(branch prediction) 알고리즘이 if 쪽에서 더 잘 이루어질 수 있다.

 

이러한 이유로 if문을 사용할 때는 if문 분기 앞쪽에 더 많이 발생하는 조건을 넣는 것이 더 유리하다.

 

 

반응형

댓글