ch4_제어문과반복문

통합 문서입니다.


1. 제어문과 반복문

제어문과 반복문

학습 목표


1. 프로그램 흐름 제어의 핵심

기본 실행 흐름은 위에서 아래로 순차 진행된다.
제어문은 이 흐름을 바꾼다.

좋은 제어문 코드는 다음 특징을 가진다.

제어문 선택 지도

분기/반복 요구사항에 따라 어떤 제어문을 선택할지 빠르게 판단할 수 있는 지도다.


2. 조건문 if / else if / else

2.1 기본 형태

if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else {
    grade = "C";
}

Java에서 조건식은 반드시 boolean이어야 한다.

// if (1) {} // 컴파일 오류(C 스타일 불가)

2.2 가독성 원칙

  1. 조건을 의미 있는 변수/메서드로 분리
  2. 중첩이 깊어지면 조기 반환(guard clause) 고려
  3. 경계값 비교(>=, >)를 명시적으로 작성

예:

if (user == null) {
    return;
}
if (!user.isActive()) {
    return;
}
process(user);

3. switch 문과 switch

3.1 전통적인 switch 문

switch (month) {
    case 12:
    case 1:
    case 2:
        season = "겨울";
        break;
    case 3:
    case 4:
    case 5:
        season = "봄";
        break;
    default:
        season = "기타";
}

break 누락 시 fall-through가 발생한다.

3.2 switch expression (최신 문법)

String season = switch (month) {
    case 12, 1, 2 -> "겨울";
    case 3, 4, 5 -> "봄";
    case 6, 7, 8 -> "여름";
    case 9, 10, 11 -> "가을";
    default -> "잘못된 값";
};

장점:


4. 반복문 for

4.1 기본 for

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

반복 횟수가 명확할 때 가장 적합하다.

for 루프 생명주기

for 문의 실행 순서(초기화 -> 조건 -> 본문 -> 증감 -> 조건 재평가)를 흐름도로 나타낸 그림이다.

4.2 향상된 for-each

int[] nums = {1, 2, 3};
for (int n : nums) {
    System.out.println(n);
}

배열/컬렉션 순회에 간결하지만 인덱스 제어가 어렵다.


5. whiledo-while

5.1 while

while (condition) {
    // 반복
}

반복 횟수보다 “조건이 만족되는 동안”이라는 의미가 중요할 때 사용한다.

5.2 do-while

do {
    // 최소 1회 실행
} while (condition);

사용자 입력을 최소 한 번은 받아야 하는 로직에서 유용하다.


6. break, continue, 라벨 제어

6.1 break

반복문 또는 switch를 즉시 종료한다.

for (int n : nums) {
    if (n < 0) break;
}

6.2 continue

현재 반복 회차만 건너뛰고 다음 회차로 간다.

for (int n : nums) {
    if (n % 2 == 0) continue;
    System.out.println(n); // 홀수만 출력
}

6.3 라벨 break/continue

중첩 반복문에서 바깥 루프를 제어할 수 있다.

outer:
for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) break outer;
    }
}

강력하지만 남용 시 가독성이 떨어지므로 신중히 사용한다.


7. 반복문 설계 패턴

7.1 누적 패턴

int sum = 0;
for (int i = 1; i <= n; i++) {
    sum += i;
}

7.2 필터 패턴

for (int n : arr) {
    if (n < 0) continue;
    // 양수만 처리
}

7.3 탐색 패턴

boolean found = false;
for (String name : names) {
    if ("kim".equals(name)) {
        found = true;
        break;
    }
}

7.4 센티넬 패턴

특정 종료값(예: 0, -1)을 입력받을 때까지 반복.


8. 무한 루프와 경계값 오류

8.1 무한 루프 예시

int i = 0;
while (i < 10) {
    // i 증가 누락 -> 무한 루프
}

8.2 오프바이원(Off-by-one) 오류

for (int i = 0; i <= arr.length; i++) { // 마지막 인덱스 초과
    System.out.println(arr[i]);
}

배열은 i < arr.length가 기본 패턴이다.


9. 성능과 가독성 관점

  1. 루프 내부에서 불변 계산은 바깥으로 이동
  2. 깊은 중첩은 메서드 분리로 단순화
  3. 조건식이 길면 boolean 변수로 의미 부여
  4. 조기 종료(break, return)를 적절히 사용해 불필요 반복 제거

10. 제어문 선택 기준

  1. 다중 분기(범위 비교 중심): if-else
  2. 하나의 값에 대한 다중 매칭: switch
  3. 반복 횟수 명확: for
  4. 종료 조건 중심: while
  5. 본문 최소 1회 실행 필요: do-while

11. 실무에서 자주 보는 실수

  1. 중괄호 생략으로 의도와 다른 분기 실행
  2. if 중첩이 너무 깊어 디버깅 어려움
  3. 반복문 내부에서 컬렉션 구조를 잘못 수정해 예외 발생
  4. break/continue 남용으로 흐름 추적 어려움
  5. 종료 조건 부정확으로 무한 루프

12. 정리


2. 문제

문제

ch4 범위(조건문, switch, 반복문, 흐름 제어) 문제입니다.


A. 조건문 기초

  1. 정수 하나를 입력받아 양수/음수/0을 판별하시오.
  2. 점수 하나를 입력받아 학점(A/B/C/D/F)을 출력하시오.
  3. 세 수를 입력받아 중간값을 출력하시오.
  4. 주민등록 연령 기준으로 성인/청소년/아동을 분류하시오.

B. switch 문제

  1. 월(1~12)을 입력받아 계절을 출력하시오.
  2. 요일 번호(1~7)를 입력받아 요일명을 출력하시오.
  3. 간단한 메뉴 선택 프로그램(1:조회, 2:등록, 3:삭제)을 switch로 구현하시오.
  4. switch expression 문법으로 기존 switch 문을 리팩터링하시오.

C. 반복문 기초

  1. n을 입력받아 1~n 합계를 구하시오 (for).
  2. n을 입력받아 구구단 n단을 출력하시오.
  3. 1~100 사이 홀수 합과 짝수 합을 각각 구하시오.
  4. 입력된 문자열을 문자 단위로 순회해 모음 개수를 세시오.

D. while / do-while

  1. 0이 입력될 때까지 정수를 입력받아 총합을 출력하시오 (while).
  2. 비밀번호를 맞출 때까지 입력받는 프로그램을 작성하시오 (do-while).
  3. 메뉴를 반복 출력하고 0 입력 시 종료하는 콘솔 앱을 작성하시오.
  4. 사용자 입력 횟수를 제한한 로그인 시뮬레이터를 구현하시오.

E. break / continue

  1. 배열에서 처음 등장하는 음수의 인덱스를 찾고 즉시 종료하시오 (break).
  2. 1~100 중 3의 배수만 건너뛰고 출력하시오 (continue).
  3. 이중 반복문에서 특정 조건 만족 시 바깥 루프까지 종료하시오 (label break).
  4. 소수 판별 루프에서 불필요 반복을 줄이도록 break를 적용하시오.

F. 패턴/응용

  1. 별 피라미드(정삼각형)를 출력하시오.
  2. 2차원 배열의 대각선 합을 구하시오.
  3. 로또 번호(중복 없는 6개)를 생성하시오.
  4. 숫자 야구 게임의 입력 검증 루프를 구현하시오.

G. 실무 시나리오형

  1. 주문 목록(int[] prices)에서 총액, 할인 적용 후 금액, 무료 배송 여부를 계산하시오.
  2. 사용자 목록을 순회하며 비활성 계정만 필터링해 출력하시오.
  3. 로그 리스트에서 에러 로그를 찾으면 즉시 관리자 알림을 보내고 순회를 중단하시오.
  4. 재고 수량이 임계치보다 낮은 상품만 추출하는 루프를 구현하시오.

H. 디버깅 문제

아래 코드의 버그를 찾고 수정하시오.

for (int i = 0; i <= arr.length; i++) {
    if (arr[i] % 2 == 0)
        continue;
    System.out.println(arr[i]);
}

점검 항목:


제출 체크리스트

  1. 반복문 종료 조건이 명확한가?
  2. 배열 순회 시 i < length를 지켰는가?
  3. 중첩 조건/중첩 반복을 함수로 분리해 가독성을 확보했는가?
  4. break/continue 사용 의도가 코드에서 명확한가?