Study/java

[백기선님의 자바 라이브 스터디] 4주차 - 선택문과 제어문

에디개발자 2020. 12. 28. 00:01
반응형

www.youtube.com/watch?v=HLnMuEZpDwU 

목표

자바가 제공하는 다양한 연산자를 학습하세요.

 

학습할 것

선택문

제어문

 

정리하기에 앞서 모든 소스는 github에 있습니다.

 

선택문

자바에서 선택문은 크게 if문과 switch문 2가지가 있습니다.

먼저 if문에 대해서 알아보겠습니다.

 

if문

if문은 크게 3가지 형태로 사용할 수 있습니다. 

  1. if ( {조건문} ) { 로직 } 
    1. if 문 내의 조건이 참일 경우 로직을 실행합니다.
  2. if ( {조건문} ) { 로직1 } else { 로직2 }
    1. if 문 내의 조건이 참일 경우 로직1을 실행합니다.
    2. if 문 내의 조건이 거짓일 경우 로직2를 실행합니다.
  3. If ( {조건문} ) { 로직1 } else if ( {조건문} ) { 로직2 } else { 로직3 }
    1. if 문 내의 조건이 참일 경우 로직1을 실행합니다.
    2. if 문 내의 조건이 거짓이고 else if 문 내의 조건이 참일 경우 로직2를 실행합니다.
    3. if 문 내의 조건과 else if 내의 조건 모두 거짓일 경우 로직 3을 실행합니다.

위 세가지에 대한 예제 코드를 작성해보겠습니다.

private static void ifElse() {
    int a = 0;
    // if문
    if (a == 0) {       // 조건이 참이므로 블록 코드 실행
        System.out.println("if문은 참이다");
    }

    // if else문
    if (a == 1) {
        System.out.println("if else문은 참이다.");
    } else {            // if문의 조건이 거짓이므로 아래 코드가 실행
        System.out.println("if else문은 거짓이다.");
    }

    // if else if else 문
    if (a == 1) {
        System.out.println("if가 참이다.");
    } else if (a == 0) {   // else if문의 조건이 참이므로 아래 코드가 실행
        System.out.println("else if가 참이다.");
    } else {
        System.out.println("else가 참이다");
    }
}

if 문은 if문 블록 내에서 다시 if문을 사용할 수도 있습니다. 

private static void 이증if문() {
    int a = 0;
    int b = 1;

    if(a == 0) {
        if(b == 0) {
            System.out.println("조건은 참이다.");
        } else {
            System.out.println("조건은 거짓이다.");
        }
    }
}

 

심심풀이 Byte Code

private static void basic_if문() {
    int a = 0;
    long b = 1L;
    if(a == 0) {
        System.out.println("....");
    }
}
 private static basic_if문()V
   L0
    LINENUMBER 11 L0    // 11번째 라인에
    ICONST_0            // stack에 int값 0을 넣는다.
    ISTORE 0            // 레지스터 0에 변수 저장
   L1
    LINENUMBER 12 L1    // 12번째 라인에
    LCONST_1            // stack에 long값 0을 넣는다.
    LSTORE 1            // 레지스터 1에 변수 저장
   L2
    LINENUMBER 13 L2
    ILOAD 0             // local varibles의 0번째 변수를 로드한다.
    IFNE L3				// L3 if문 실행
   L4
    LINENUMBER 14 L4    // 여긴 sysout 실행하겠다라는 코드
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "...."
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L3
    LINENUMBER 16 L3
   FRAME APPEND [I J]
    RETURN
   L5
    LOCALVARIABLE a I L1 L5 0
    LOCALVARIABLE b J L2 L5 1
    MAXSTACK = 2
    MAXLOCALS = 3

 

switch case문

switch case문은 if문이 여러개일 경우 실행속도가 느려지는 단점을 보완할 수 있습니다.

if문은 조건이 참인 경우를 찾을 때까지 한라인씩 실행합니다. 하지만 switch문은 조건에 맞는 case에 바로 찾아갈 수 있어서 조건이 많은 경우에는 실행속도가 빠릅니다.

 

간단한 코드로 확인할 수 있습니다.

private static void if문과switch문실행속도비교() {
    StopWatch ifStopWatch = new StopWatch();
    int a = 10;

    int iterateSize = 1000000000;

    ifStopWatch.start();
    for (int i = 0; i < iterateSize; i++) {
        if( a == 1 ) {}
        else if (a == 2) {}
        else if (a == 3) {}
        else if (a == 4) {}
        else if (a == 5) {}
        else if (a == 6) {}
        else if (a == 7) {}
        else if (a == 8) {}
        else if (a == 9) {}
        else if (a == 10) {}
    }

    ifStopWatch.stop();

    System.out.println("if문 실행속도 ->" + ifStopWatch.prettyPrint());

    StopWatch switchStopWatch = new StopWatch();
    switchStopWatch.start();
    for (int i = 0; i < iterateSize; i++) {
        switch (a) {
            case 1: break;
            case 2: break;
            case 3: break;
            case 4: break;
            case 5: break;
            case 6: break;
            case 7: break;
            case 8: break;
            case 9: break;
            case 10: break;
        }
    }

    switchStopWatch.stop();
    System.out.println("switch문 실행속도 ->" + switchStopWatch.prettyPrint());
}

조건1) if문 10개 조건 중 맨 마지막 조건일 경우

조건2) 어마어마하게 많은 루프를 돌 경우

위 두 조건일 경우는 switch문이 if문보다 매우 빠르다는 것을 알 수 있습니다.

무조건 switch문을 사용하라는 것은 아닙니다. 루프가 예제처럼 기하급수적인 경우가 아닌 경우에는 속도차이가 나지 않을 정도로 볼 수 있습니다.

 

Switch문 조건

Switch의 조건문에는 wrapper 된 변수를 사용할 수 있습니다. 내부에서 unWrap하여 case문의 조건과 비교하여 로직을 실행합니다.

private static void switch문() {
    Integer a = 0;

    switch (a) {
        case 0:
            System.out.println("0");
            break;
        case 1:
            System.out.println("1");
            break;
        default:
            System.out.println("default");
    }
}

 

break의 중요성

switch case문은 switch문에서 값을 확인하고 매칭되는 case를 찾아갑니다. 그리고 break를 찾을 때까지 실행됩니다.

private static void switch_break() {
    int a = 0;
    switch (a) {
        case 0:
            System.out.println("0");    // 실행됨
        case 1:
            System.out.println("1");    // 실행됨
        case 2:
            System.out.println("2");    // 실행됨
            break;                      // break문을 찾고 종료됨
        case 3:
            System.out.println("3");
            break;
        default:
            System.out.println("default");
    }
}

 

default

if문의 else와 비슷한 기능을 하는 기능은 switch문의 default입니다.

필수적으로 선언할 필요는 없지만 저는 되도록이면 default인 경우도 선언해줘야한다고 생각합니다.

내가 생각하는데로 로직이 흐르지 않을 경우 default 처리를 해줘야 프로그램 안정성이 높아진다고 생각합니다.

private static void switch_default() throws Exception {
    int a = 9;
    switch(a) {
        case 1:
            break;
        case 2:
            break;
        default:
            throw new Exception();  // 데이터 흐름이 원하는 데로 되지 않을 경우 Exception을 던지는 예
    }
}

 

반목문

반복문에는 for, while, do-while, for-each, iterator 등이 있습니다. 한개씩 예제 소스를 작성해가면서 알아보겠습니다.

 

for문

for문은 고정된 값만큼 루프를 실행시키고 싶을 경우 사용합니다.

for ( 초기화; 표현식; 명령문 ) { 로직 } 으로 구성되어 있습니다. 간단한 예제로 살펴보겠습니다.

private static void basic_for문() {
    for (int i = 0; i < 10; i++) {
        System.out.println(i);   // 결과값으로 0,1,2,3,4,5,6,7,8,9 가 출력됨
    }
}

break 사용했을 경우 루프 중 빠져 나올 수 있습니다.

private static void break_for문() {
    for (int i = 0; i < 10; i++) {
        System.out.println(i);      // 결과값으로 0,1,2,3,4 가 출력됩니다.
         if(i == 4) {
             break;
         }
    }
}

continue를 사용하여 블럭 내 로직을 건너뛸 수 있습니다.

private static void break_continue() {
    for (int i = 0; i < 10; i++) {
         if(i == 4) {
             continue;
         }
        System.out.println(i);		// 4를 제외한 값이 출력됨
    }
}

 

while문

조건문이 충족할 때까지 무한 루프를 실행시킬 경우 사용하는 반복문입니다.

while( {조건문} ) { 로직 }

private static void while문() {
    int a = 0;
    while (a < 5) {
        System.out.println(a);    // 0,1,2,3,4
        a++;
    }
}

break를 사용하여 종료시킬 수도 있습니다.

private static void while_break() {
    int a = 0;
    while(true) {
        if(a > 5) {
            break;
        }
        System.out.println(a);    // 0,1,2,3,4,5 
        a++;
    }
}

 

do-while

while과 비슷한 기능이지만 차이점은 조건문을 언제 비교하느냐입니다.

while문은 블록 로직을 실행하기 전에 조건문을 파악하지만 do-while문은 먼저 로직을 실행시키고 조건문을 파악합니다.

private static void doWhile문() {
    int a = 0;

    while (a != 0) {  // 실행안됨
        System.out.println("while문 : " + a);
    }

    do {              // 실행됨
        System.out.println("do while문 : " + a);
    } while(a != 0);
}

 

for-each문

for문의 향상된 버전입니다. 일반적인 for문은 표현식에서 명시한 값만큼 루프를 도는 형식이었습니다. 하지만 for-each는 리스트의 Size만큼 루프를 돌기때문에 코드 상 더 직관적이고 가독성을 높힐 수 있습니다.

단, 일반적인 for문에서는 index값을 가져올 수 있지만 for-each문에서는 index값을 가져올 수는 없습니다. 

private static void foreach문() {
    List<Integer> intArray = Arrays.asList(1,2,3,4,5,6,7);

    for (int a : intArray) {
        System.out.println(a);
    }
}

for-each문은 내부에서 iterator를 사용합니다. 

  1. for문이 시작되는 시점에서 iterator 객체를 생성합니다.
  2. iterator 객체에서 cursor와 hasNext() 메서드를 이용하여 루프를 진행합니다.
    1. cursor는 현재 index값
    2. hasNext는 다음 index에 해당하는 값을 가져온다.
    3. cursor가 iterator객체의 사이즈와 같아지면 루프를 중지한다.

다음글에서 과제도 진행할 예정입니다. 

반응형