[Java] 04. 제어문


Study/Java  2020. 5. 4. 16:00

안녕하세요. 명월입니다.


이 글은 Java에서 사용되는 제어문에 대한 글입니다.


제어문이란 프로그램의 순서를 제어하거나 수행 횟수를 결정하는 키워드라고 정의되어 있습니다.

예를 들면, 관계 연산자나 논리 연산자를 통해서 두 개의 변수로 boolean의 값을 받으면 true일 때의 처리와 false일 때의 처리를 제어하거나, 몇 번의 수행할 처리를 반복해서 처리하게 하는 방법 등을 제어하는 것입니다.

이 제어문의 경우는 C언어에서부터 파생되어온 문법으로 Java나 C#등 거의 모든 프로그램 언어가 표현하는 문법은 다를지언정 처리되는 방식은 대부분 같습니다.


제어문은 처리되는 방식에 따라 크게 조건문, 선택문, 반복문, 분기문으로 구분됩니다.

if ~ else if ~ else

if ~ else if ~ else는 boolean의 값에 따라 처리되는 조건문입니다.

① if(조건)           => 조건이 참(true)이면 "처리 스택"을 실행한다.
    처리 스택;

② if(조건)           => 조건이 참(true)이면 "처리 스택 1"을 실행한다.
    처리 스택 1;
  else              => 거짓(false)이면 "처리 스택 2"를 실행한다.
    처리 스택 2;


③ if(조건1)          => 조건1이 참(true)이면 "처리 스택 1"을 실행한다.
    처리 스택 1;      
  else if(조건2)     => 조건1이 거짓(false)이고 조건2가 참(true)이면 "처리 스택 2"를 실행한다.
    처리 스택 2;
  else              => 조건1과 조건2가 둘 다 거짓이면 "처리 스택 3"을 실행하라.
    처리 스택 3;

쉽게 설명하면 if문의 조건이 참(true)이면 해당 스택을 실행하는 구조입니다. 마지막에 else가 있으면 모두 거짓일 경우 else의 스택을 실행하면 됩니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 부울 값 설정 = true
    boolean a = true;
    // 변수 a가 true면
    if (a) {
      // 콘솔 출력
      System.out.println("first condition = true");
    }
    // 부울 값 설정 = false
    a = false;
    // 변수 a가 true면
    if (a) {
      // 콘솔 출력
      System.out.println("second condition = true");
    // 변수 b가 false이면
    } else {
      // 콘솔 출력
      System.out.println("second condition = false");
    }
    // 변수 b에 값 2를 설정
    int b = 2;
    // 변수 b가 1이면
    if (b == 1) {
      // 콘솔 출력
      System.out.println("third condition b = 1");
    // 변수 b가 2이면
    } else if (b == 2) {
      // 콘솔 출력
      System.out.println("third condition b = 2");
    // 변수 b가 1또는 2가 아니면
    } else {
      // 콘솔 출력
      System.out.println("third condition = false");
    }
  }
}

위 예제를 설명하면 첫번째 조건에서 a의 변수의 조건을 확인합니다.

a의 부울 값이 true라면 if(a)에 있는 스택 영역이 실행 될 것입니다. a라는 변수에 true를 넣었기 때문에 콘솔에 true라는 메시지가 표시됩니다.


두번째 조건식에서는 if ~ else 조건식인데 변수 a가 true면 첫번째 스택 영역을, false라면 else 밑의 스택 영역을 실행합니다.

두번째 조건식이 오기 전에 false로 설정했기 때문에 콘솔에는 false가 출력이 되었습니다.


세번째 조건식은 변수의 b의 값을 관계 연산자로 값의 true, false를 확인합니다.

b의 값을 2로 설정했기 때문에 if (b == 2)의 스택 영역이 실행되므로 콘솔에는 b = 2라는 값이 출력 되었습니다.

switch ~ case

switch ~ case는 선택문으로써 if ~ else if ~ else 와 비슷한 처리를 합니다.

switch(조건 변수) {
  case 값1:
    처리 1;
    break;
  case 값2:
    처리 2;
    break;
  case 값3:
    처리 3;
    break;
  ...
  default:
    처리;
    break;
}

switch ~ case에서 중요한 점은 break입니다. switch의 조건 변수에 해당하는 값을 찾아 case로 찾아가는 데 break가 없으면 해당 case만 처리하는 것이 아니라 선택되어 있는 case의 아래 스탭도 모두 처리가 되어 버립니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 변수 data에 10을 설정
    int data = 10;
    // data의 조건 변수
    switch (data) {
    // data가 10인 경우
    case 10:
      // 콘솔 출력
      System.out.println("data = 10");
      // switch 빠져나오기
      break;
    // data가 20인 경우
    case 20:
      // 콘솔 출력
      System.out.println("data = 20");
      // switch 빠져나오기
      break;
    // case에서 선택되지 않았을 경우
    default:
      // 콘솔 출력
      System.out.println("default");
      // switch 빠져나오기
      break;
    }
    // 합산 변수 설정
    int sum = 0;
    // data의 조건 변수
    switch (data) {
    // data가 10인 경우
    case 10:
      // 합산 변수에 10을 더한다.
      sum += 10;
      // break가 없기 때문에 10을 선택하면 case 9도 처리된다.
    // data가 9인 경우
    case 9:
      // 합산 변수에 9을 더한다.
      sum += 9;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 8인 경우
    case 8:
      // 합산 변수에 8을 더한다.
      sum += 8;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 7인 경우
    case 7:
      // 합산 변수에 7을 더한다.
      sum += 7;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 6인 경우
    case 6:
      // 합산 변수에 6을 더한다.
      sum += 6;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 5인 경우
    case 5:
      // 합산 변수에 5을 더한다.
      sum += 5;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 4인 경우
    case 4:
      // 합산 변수에 4을 더한다.
      sum += 4;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 3인 경우
    case 3:
      // 합산 변수에 3을 더한다.
      sum += 3;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 2인 경우
    case 2:
      // 합산 변수에 2을 더한다.
      sum += 2;
      // break가 없기 때문에 처리가 계속 내려간다.
    // data가 1인 경우
    case 1:
      // 합산 변수에 1을 더한다.
      sum += 1;
    }
    // 콘솔 출력
    System.out.println("sum = " + sum);
  }
}

위 예제를 보면 첫 번째 예제는 data의 값에 따라 콘솔이 출력된 것을 확인할 수 있습니다.

그러나 두번째 예제는 data가 10일 경우 case에 break가 없기 때문에 case 9 ~ 1까지 모두 sum이 합산되어 최종 1부터 10까지 더한 값이 되었습니다.

for

for 문은 아마 java에서 if와 더불어 가장 많이 사용되는 제어문이지 않을까 싶습니다.

for 문의 조건식에는 세미 콜론(;)를 구분으로 초기값과 조건식, 증감치의 값을 설정하게 됩니다.

for (초기값; 조건식; 증감치) {
  처리;
}

초기값에는 조건식에 사용될 변수를 설정하고 그 초기값의 변화를 증감치에 설정하는 구성으로 되어있습니다. 조건식과 증감식에는 반드시 초기값의 값을 넣을 필요는 없습니다.

조건식이 true라면 처리가 실행되고 실행이 끝나면 다시 조건식을 확인합니다. 그 때 true라면 다시 처리가 실행되겠습니다.

만약 조건식에 false가 나오는 조건을 구성하지 못하고 영원히 true 상황이 된다면 무한 루프, 즉 for이 끝나지 않는 상태가 될 것입니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 초기값 i는 0을 설정한다.
    // 조건식의 i<10의 조건이 true일 경우 아래의 콘솔 출력을 한다.
    // 증감식은 아래의 스택 영역이 실행되고 난 후에 i++를 실행한다.
    for (int i = 0; i < 10; i++) {
      // 콘솔 출력
      System.out.println("i = " + i);
    }

    int a = 0;
    // 조건식과 증감식에는 반드시 초기식을 사용할 필요는 없다.
    // 하지만 가독성을 위해 초기식 사용을 권장한다.
    for (int i = 0; a < 1; a++) {
      // 콘솔 출력
      System.out.println("a = " + a);
    }
  }
}

for문은 디자인 패턴에서의 iterator 패턴을 구현할 수 있습니다. 배열이나 리스트, stream 식의 경우, 배열의 한개의 원소를 받아서(.next()) null인지 확인(.has())한 후 null이 아니면 스택 영역을 실행하는 패턴을 구현할 수 있습니다.

이건 나중에 배열이나 list를 소개할 때 묶어서 설명하겠습니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // i < 1은 영원히 true, 즉, 무한 루프 상태가 되기 때문에 이 프로그램은 종료하지 않는다.
    for (int i = 0; i < 1; i--) {
      // 콘솔 출력
      System.out.println("i = " + i);
    }
    // 배열 설정
    int array[] = {1,2,3,4,5};
    // iterator 패턴
    for(int item : array) {
      // 콘솔 출력
      System.out.println(item);
    }
  }
}

while

while문은 for문에서 초기식과 증감식을 뺀 조건식만 있는 반목문입니다.

while (조건식) {
  처리;
}

while의 경우는 초기식, 조건식을 별도로 처리하기 때문에 무한 루프에 빠지는 것을 항상 주의해야 합니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 초기 변수값
    int i = 0;
    // i<10가 참이면 스택 영역 실행
    while (i < 10) {
      // 콘솔 출력
      System.out.println("i = " + i);
      // i변수 값 증가 
      i++;
    }
  }
}

do ~ while

do ~ while은 while식과 비슷한데 스택 영역이랑 조건식이 뒤집혀 있는 형태입니다.

즉, while은 조건식을 확인(true, false)하고 스택 영역을 실행하지만, do ~ while은 스택 영역을 실행하고 조건식으로 다시 실행할 것인지 설정하는 것입니다.

do {
  처리;
} while(조건식); // while뒤에 반드시 세미콜론(;)

그러므로 do ~ while은 조건식과 관계없이 처리 식을 반드시 한 번은 실행합니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 초기 변수값
    int i = 0;
    do {
      // 콘솔 출력
      System.out.println("i = " + i);
      // i변수 값 증가
      i++;
      // i<10가 참이면 스택 영역 실행
    } while (i < 10);
    
    // 변수 재설정
    i = 1000;
    do {
      // 콘솔 출력
      System.out.println("i = " + i);
      // i변수 값 증가
      i++;
      // i<10가 참이면 스택 영역 실행
    } while (i < 10);
    // do ~ while은 반드시 한번은 실행하기 떄문에 조건식이 처음부터 틀리더라도 실행된다.
  }
}

break

break는 switch ~ case에서 잠깐 설명한 분기문입니다. break는 사실 for이나 while, do ~ while과 더 친숙한 분기문입니다.

반복문은 조건식에 의해 반복의 횟수가 정해져 있는데, 이 조건식을 아닌 특정 조건식에 의해 반복문을 탈출할 때 사용하는 제어문입니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 변수 선언
    int i = 0;
    // 조건식에 true값이 들어가면 영원한 루프인 무한 루프에 빠집니다.
    while (true) {
      // i가 10부터 클 경우
      if (i > 10) {
        // 콘솔 출력
        System.out.println("break!!");
        // while의 루프를 중단한다.
        break;
      }
      // 콘솔 출력
      System.out.println("i = " + i);
      // i를 1 증가
      i++;
    }
  }
}

이중 삼중의 반복문일 경우 반복문에 라벨 지정을 하여 break를 통해 특정 반복문을 탈출 할 수 있습니다.

라벨이 지정되어 있지 않으면 가장 가까운 반목문을 탈출합니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 변수 선언
    int i = 0;
    // 조건식에 true값이 들어가면 영원한 루프인 무한 루프에 빠집니다.
    // 반목문 앞에 라벨을 지정할 수 있습니다. 라벨 test1
    test1: while (true) {
      // 중첩 반목문.  라벨 test2
      test2: for (int j = 0; j < 10; j++) {
        // i가 10부터 클 경우
        if (i > 10) {
          // 콘솔 출력
          System.out.println("break!!");
          // while의 루프를 중단한다.
          break test1;
        }
        // 콘솔 출력
        System.out.println("i = " + i);
        System.out.println("j = " + j);
        // j를 2로 나눈 나머지가 0, 즉 짝수 일 때 i를 1 증가
        if (j % 2 == 0) {
          i++;
        }
      }
    }
  }
}

라벨 지정하여 break를 설정하는 건 가독성에 매우 좋지 않기 때문에 권장하지 않고, 나중에 함수 영역을 알게 되면 분기별로 함수를 나누는 것이 좋습니다.

continue

continue는 용법은 break와 같습니다. 차이점은 break는 반복문을 탈출하는 것이라면 continue는 현재 실행 중인 스택만 skip하는 것입니다.

public class Test {
  // 실행 함수
  public static void main(String[] args) {
    // 0부터 9까지 반복문을 실행한다.
    for (int i = 0; i < 10; i++) {
      // i의 값을 2로 나눈 나머지가 0, 즉 짝수의 경우
      if (i % 2 == 0) {
        // 아래의 콘솔 출력을 실행하지 않고 다음 증감식으로 이동한다.
        continue;
      }
      // 콘솔 출력
      System.out.println("i = " + i);
    }
  }
}

위 예제에서 for문으로 i가 0부터 9까지의 반복문을 실행합니다. continue대신 break를 사용하면 for문을 빠져나가기 때문에 콘솔에 아무것도 출력이 되지 않습니다. 그러나 continue는 반복문 탈출이 아니고 다음 스택으로 넘기는 분기문이기 때문에 반복문은 계속 실행됩니다.

단, i % 2 == 0, 즉 짝수일 떄는 콘솔 출력이 된지 않아서 홀수만 출력이 되었습니다.


여기까지 Java에서 사용되는 제어문에 대한 글이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.