제리의 배움 기록

[Java] if, switch 누가 더 빠를까? 본문

자바

[Java] if, switch 누가 더 빠를까?

제리92 2021. 12. 6. 11:48

조건에 따라 실행 흐름을 분기해야 하는 경우 우리는 조건문을 사용합니다.

Java에는 if-else / switch 두가지 조건문이 있습니다.

이 중 어떤 방식이 더 효율적인지, 무엇을 쓰는게 좋을지 비교해보고자 합니다.

우선, switch를 사용할 수 없는 것들은 선택의 여지 없이 if-else를 사용하면 됩니다.

switch 비교대상변수 참조

다음으로 if-else, switch 두가지 방식 모두 사용할 수 있는 경우가 있습니다.

동일한 로직을 두 방법으로 구현하여 변환된 바이트 코드를 비교해보며 차이를 알아보겠습니다.

if

자바코드

public class ConditionTest1Main {

    void doIfStatement() {
        int number = 5;

        if (number == 1) {
            method1();
        } else if (number == 2) {
            method2();
        } else {
            method3();
        }
    }

    void method1(){
        System.out.println("method1");
    }

    void method2(){
        System.out.println("method1");
    }

    void method3(){
        System.out.println("method1");
    }
}

바이트코드

// class version 52.0 (52)
// access flags 0x21
public class ConditionTest1Main {

  // compiled from: ConditionTest1Main.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 1 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this LConditionTest1Main; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x0
  doIfStatement()V
   L0
    LINENUMBER 4 L0
    ICONST_5
    ISTORE 1
   L1
    LINENUMBER 6 L1
    ILOAD 1
    ICONST_1
    IF_ICMPNE L2
   L3
    LINENUMBER 7 L3
    ALOAD 0
    INVOKEVIRTUAL ConditionTest1Main.method1 ()V
    GOTO L4
   L2
    LINENUMBER 8 L2
   FRAME APPEND [I]
    ILOAD 1
    ICONST_2
    IF_ICMPNE L5
   L6
    LINENUMBER 9 L6
    ALOAD 0
    INVOKEVIRTUAL ConditionTest1Main.method2 ()V
    GOTO L4
   L5
    LINENUMBER 11 L5
   FRAME SAME
    ALOAD 0
    INVOKEVIRTUAL ConditionTest1Main.method3 ()V
   L4
    LINENUMBER 13 L4
   FRAME SAME
    RETURN
   L7
    LOCALVARIABLE this LConditionTest1Main; L0 L7 0
    LOCALVARIABLE number I L1 L7 1
    MAXSTACK = 2
    MAXLOCALS = 2
...
}

L1부터 L4까지가 if문이 변환된 바이트코드입니다.

1)L1는 비교로직을 수행하고 조건문을 통과하면 L3가 실행되고, L4로 넘어가 if문이 종료되지만,
통과하지 못하면 IF_ICMPNE L2로 L2로 넘어가게 됩니다.
2)L2로 넘어가 비교로직을 수행하고 조건문을 통과하면 L6 수행후 L4로 넘어가 if문이 종료되지만,
통과하지 못하면 IF_ICMPNE L5로 L5로 넘어가게 됩니다.
3)L5는 else 조건이기 때문에 비교로직 없이 내부 로직이 수행되고 L4로 넘어가 if문을 종료하게 됩니다.

이 과정을 보면 if-else 구문은, true가 되는 조건을 만나기까지 if절에 작성된 차례대로 비교연산을 계속해서 수행하여야 합니다.
if절이 10개 정도 된다면, 마지막 조건에 걸리는 값이더라도 항상 앞에 9번의 조건을 수행해야하는 비효율이 있습니다.

[특징 요약]

  • if-else 구문의 조건들 중 만족하는 조건이 나타낼 때 까지 조건을 체크합니다.
  • 따져야 하는 조건이 많을 수록 연산량이 늘어납니다.
  • 확률이 높은 조건부터 작성하면, 조건 체크 연산이 줄어드므로 효율적입니다.
    => 조건들의 확률이 비슷하지 않고 특정 조건의 확률이 높은 경우는 switch 보다 빠를 수 있습니다.

Switch

자바코드

(if를 사용한 코드에서 doIfStatement 메서드 내부 구현만 swtich로 변경)

void doIfStatement() {
        int number = 5;

        switch (number){
            case 1:
                method1();
                break;
            case 2:
                method2();
                break;
            default:
                method3();
        }
    }

바이트코드

// class version 52.0 (52)
// access flags 0x21
public class ConditionTest2Main {

  // compiled from: ConditionTest2Main.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 1 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this LConditionTest2Main; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x0
  doIfStatement()V
   L0
    LINENUMBER 4 L0
    ICONST_5
    ISTORE 1
   L1
    LINENUMBER 6 L1
    ILOAD 1
    LOOKUPSWITCH
      1: L2
      2: L3
      default: L4
   L2
    LINENUMBER 8 L2
   FRAME APPEND [I]
    ALOAD 0
    INVOKEVIRTUAL ConditionTest2Main.method1 ()V
   L5
    LINENUMBER 9 L5
    GOTO L6
   L3
    LINENUMBER 11 L3
   FRAME SAME
    ALOAD 0
    INVOKEVIRTUAL ConditionTest2Main.method2 ()V
   L7
    LINENUMBER 12 L7
    GOTO L6
   L4
    LINENUMBER 14 L4
   FRAME SAME
    ALOAD 0
    INVOKEVIRTUAL ConditionTest2Main.method3 ()V
   L6
    LINENUMBER 16 L6
   FRAME SAME
    RETURN
  ...
}

L1부터 L4까지 switch문이 변환된 바이트코드 입니다.
L1을 보시면 if-else와의 가장 큰 차이인 LOOKUPSWITCH 구문을 보실 수 있습니다.
LOOKUPSWITCH 방식은 if-else 처럼 비교연산을 하지 않고 표현식 값을 이용해 탐색함으로써 내부적으로 아래와 같이 값에 해당하는 jump table을 생성됩니다.

LOOKUPSWITCH
      1: L2
      2: L3
      default: L4

만족하는 조건값을 찾을때까지 비교연산 없이 바로 해당 실행구문으로 점프할 수 있다는 점에서 효율적이지만,
jump table 생성 비용의 오버헤드가 있습니다.

[요약]

  • 조건 값을 이용하여 빠른시간에 탐색할 수 있는 jump table을 생성합니다.
  • 조건이 많을 때와 여러기능을 유사한 빈도로 사용할 때는 if-else 보다 성능이 빠를 수 있습니다.

 

[참고]
if문 vs switch문
geeksforgeeks - switch vs else

Comments