[아이티센 부트캠프] (반복문)

이언덕·2026년 3월 20일

아이티센 부트캠프

목록 보기
6/115
post-thumbnail

[반복문]

개념

프로그램을 만들다 보면 같은 코드를 여러 번 실행해야 할 때가 많다.
예를 들어 1부터 10까지 출력하거나, 1부터 100까지 더하거나, 구구단을 여러 줄 출력하는 작업은 한 번만 실행해서 끝나는 코드가 아니다.

이럴 때 같은 코드를 여러 줄 복붙하는 대신, 같은 동작을 자동으로 반복하게 만드는 문법을 사용한다. 이것이 반복문이다.

자바에서 이번에 정리할 반복문은 for문과 while문이다.

  • for문: 반복 횟수가 보일 때 적합하다.
  • while문: 조건이 만족되는 동안 반복할 때 적합하다.

즉, 이번 범위의 중심은
for문으로 반복의 기본 구조를 이해하고, while문으로 조건 중심 반복을 이해하는 것이다.




1. for문

개념

for문은 반복 횟수가 정해져 있을 때, 또는 시작값부터 종료값까지 반복해야 할 때 가장 많이 쓰는 반복문이다.

예를 들면 이런 경우다.

  • 1부터 10까지 출력
  • 10번 반복
  • 1단부터 9단까지 구구단 출력
  • 1부터 100까지 누적합 구하기

즉, for문은 횟수 중심 반복이라고 이해하면 된다.



핵심 특징

기본 문법은 아래와 같다.

for (초기식; 조건식; 증감식) {
    반복할 코드
}

각 부분의 역할은 다음과 같다.

  • 초기식: 시작값을 준비한다.
  • 조건식: 반복을 계속할지 검사한다.
  • 증감식: 한 번 반복이 끝날 때마다 값을 바꾼다.

for문은 항상 아래 순서로 움직인다.

  1. 초기식 실행
  2. 조건식 검사
  3. 조건이 true면 코드 실행
  4. 증감식 실행
  5. 다시 조건식 검사

즉, 초기식은 처음 한 번만 실행되고, 그 뒤에는
조건식 → 코드 실행 → 증감식
순서가 반복된다.



코드 예제

예제: ForTest1

for (int num = 1; num <= 10; num++)
    System.out.println(num);

// 출력결과
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10

이 코드는 1부터 10까지 출력하는 가장 기본적인 for문이다.

  • int num = 1에서 num을 1로 시작한다.
  • num <= 10이 참인 동안 반복한다.
  • num++ 때문에 한 번 반복할 때마다 1씩 증가한다.

그래서 1, 2, 3, ... 10이 차례대로 출력된다.



헷갈리기 쉬운 부분

반복문을 처음 보면 1부터 10까지 출력한다만 눈에 들어오고, 값이 언제 바뀌는지는 놓치기 쉽다.

for문은 항상 이렇게 읽어야 한다.

  • 어디서 시작하는가
  • 언제까지 반복하는가
  • 한 번 돌 때마다 값이 어떻게 바뀌는가

이 세 가지를 먼저 보면 훨씬 덜 헷갈린다.




2. 증감식과 제어 변수

for문은 초기식, 조건식, 증감식이 함께 반복 흐름을 만든다.
이때 반복문 안에서 반복 횟수를 조절하는 변수를 제어 변수라고 한다.

중요한 점은 두 가지다.

  • 증감식이 바뀌면 반복 흐름도 바뀐다.
  • 제어 변수를 어디서 선언했는지에 따라 반복문 밖에서 사용할 수 있는지가 달라진다.

코드 예제

예제: ForTest1

for (int num = 1; num <= 10; num += 2)
    System.out.println(num);

// 출력결과
// 1
// 3
// 5
// 7
// 9

이번에는 num += 2를 사용했다.
즉, 한 번 반복할 때마다 2씩 증가한다.

그래서 1, 3, 5, 7, 9처럼 홀수만 출력된다.



예제: ForTest1

for (int num = 1; num <= 30; num += 2)
    System.out.println(num);

// System.out.println(num);  // 에러

여기서 num은 for문 안에서 선언했다.
그래서 반복문이 끝난 뒤에는 사용할 수 없다.

즉, 이 변수는 이 반복문 안에서만 잠깐 쓰는 변수다.



예제: ForTest1_1

int num;

for (num = 1; num <= 10; num++)
    System.out.println(num);

System.out.println();

for (num = 1; num <= 10; num += 2)
    System.out.println(num);

System.out.println(num);

// 출력결과
// 1
// 2
// ...
// 10
//
// 1
// 3
// 5
// 7
// 9
// 11

이번에는 num을 for문 밖에서 먼저 선언했다.
그래서 반복문이 끝난 뒤에도 num을 계속 사용할 수 있다.

여기서 중요한 점은 마지막에 남는 값이 9가 아니라
증감식까지 실행된 뒤의 값인 11이라는 점이다.



예제: ForTest3

int month = 1;

for (; month <= 12; month++)
    System.out.print(month + "월 ");

System.out.println();
System.out.println(month);

// 출력결과
// 1월 2월 3월 4월 5월 6월 7월 8월 9월 10월 11월 12월
// 13

여기서도 원리는 같다.

  • 12월을 출력한다.
  • month++가 실행되어 13이 된다.
  • 13 <= 12는 거짓이므로 반복이 끝난다.

그래서 마지막에 13이 남는다.

헷갈리기 쉬운 부분

초보자는 반복문이 끝나면 마지막 출력값이 그대로 남아 있을 것 같다고 느끼기 쉽다.
하지만 실제로는 출력 후 증감식까지 실행된 값이 남는다.

또 for문 괄호 안에서 선언한 변수는 그 반복문 안에서만 쓸 수 있다는 점도 같이 기억해야 한다.



참고

고정된 값을 반복 조건에 넣을 때는 숫자를 직접 쓰는 대신 상수를 써도 된다.

final int NUM = 20;

for (int n = 1; n < NUM; n++)
    System.out.print(n + " ");

이건 반복문 문법 자체보다, 고정된 값을 읽기 좋게 관리하는 습관에 가깝다.




3. for문으로 누적값 구하기

개념

for문은 단순히 여러 번 출력하는 데만 쓰이지 않는다.
반복하면서 값을 계속 더해 가는 누적 처리에도 많이 사용한다.

예를 들어 1부터 10까지의 합을 구하려면, 숫자를 하나씩 꺼내면서 이전까지의 합에 계속 더해야 한다.

이럴 때는 반복문 밖에서 누적용 변수를 먼저 만들고, 반복문 안에서 그 값을 조금씩 바꿔 가야 한다.



코드 예제

예제: ForTest4

int sumV = 0;

for (int n = 1; n <= 10; n++) {
    sumV += n;
}

System.out.println(sumV);

// 출력결과
// 55

이 코드는 1부터 10까지의 합을 구한다.

sumV += n은 아래와 같은 뜻이다.

sumV = sumV + n;

즉, 현재까지의 합에 현재 숫자를 더해서 다시 저장하는 식이다.

데이터 흐름

시작 전

  • sumV = 0

첫 번째 반복

  • n = 1
  • sumV += 1
  • 결과: sumV = 1

두 번째 반복

  • n = 2
  • sumV += 2
  • 결과: sumV = 3

세 번째 반복

  • n = 3
  • sumV += 3
  • 결과: sumV = 6

네 번째 반복

  • n = 4
  • sumV += 4
  • 결과: sumV = 10

이런 식으로 계속 누적된다.

즉, sumV는 한 번에 완성되는 값이 아니라, 반복할 때마다 조금씩 커지는 값이다.



누적값을 다시 쓰려면 초기화가 필요하다

예제: ForTest4

sumV = 0;

for (int n = 1; n <= 10; n++) {
    sumV += n * n;
}

System.out.println(sumV);

// 출력결과
// 385

이번에는 그냥 n을 더하는 것이 아니라 n * n, 즉 제곱값을 더한다.
그래서 1² + 2² + 3² + ... + 10²의 합이 구해진다.

여기서 중요한 점은, 두 번째 반복문을 시작하기 전에 sumV = 0;으로 다시 초기화했다는 것이다.

첫 번째 누적이 끝난 뒤에는 sumV 안에 이미 값이 들어 있다.
그 상태에서 바로 또 누적하면, 이전 결과에서 계속 더하게 된다.

그래서 다른 계산을 다시 시작하려면 먼저 값을 비워줘야 한다.



짝수 합, 홀수 합 구하기

예제: ForTest4

int evenNum = 0;
int oddNum = 0;

for (int num = 1; num <= 100; num++) {
    if (num % 2 == 0) {
        evenNum += num;
    }
    if (num % 2 == 1) {
        oddNum += num;
    }
}

System.out.println("짝수의 합은 " + evenNum + "이고");
System.out.println("홀수의 합은 " + oddNum + "이다");

// 출력결과
// 짝수의 합은 2550이고
// 홀수의 합은 2500이다

이 코드는 반복문과 조건문을 함께 사용한 예제다.

  • for문: 1부터 100까지 반복
  • if문: 짝수인지 홀수인지 선택
  • +=: 필요한 값만 누적

즉, 반복문은 숫자를 하나씩 꺼내고, if문은 그중에서 필요한 숫자만 골라낸다.



헷갈리기 쉬운 부분

sumV = n과 sumV += n은 완전히 다르다.

sumV = n;

이건 현재 숫자로 덮어쓰기만 한다.



sumV += n;

이건 지금까지의 값에 현재 숫자를 누적한다.

또 누적용 변수는 이전 계산 결과가 남아 있는 변수이기 때문에,
다른 계산을 시작하려면 초기화가 필요하다.



4. for문의 다양한 활용

개념

for문은 숫자만 반복하는 문법이 아니다.
문자도 반복할 수 있고, 어떤 값부터 어떤 값까지보다 그냥 몇 번 반복하느냐만 중요한 경우도 있다.

즉, for문은 모양은 같아도 무엇을 기준으로 반복하느냐에 따라 여러 방식으로 활용된다.



문자도 for문으로 반복할 수 있다

예제: ForTest5

char letter = 'A';

for (int n = 0; n < 10; n++)
    System.out.print(letter);

System.out.println("\n----------------");

for (int n = 0; n < 10; n++)
    System.out.print(letter++);

// 출력결과
// AAAAAAAAAA
// ----------------
// ABCDEFGHIJ

첫 번째 반복문은 letter 값을 바꾸지 않고 그대로 출력만 한다.
그래서 같은 문자 A가 10번 반복해서 출력된다.

두 번째 반복문은 letter++를 사용했다.
char는 문자를 저장하지만, 내부적으로는 문자에 대응하는 숫자 값을 가진다.
예를 들어 A는 65, B는 66, C는 67처럼 이어진다.

그래서 letter++를 하면 현재 문자를 먼저 출력한 뒤,
그 문자의 코드값을 1 증가시킨다.
즉, A 다음에는 B, 그다음에는 C가 되어 문자가 하나씩 바뀌며 출력된다.



예제: ForTest5

for (char m = 'A'; m <= 'Z'; m++)
    System.out.print(m);

// 출력결과
// ABCDEFGHIJKLMNOPQRSTUVWXYZ

이 코드는 char 자체를 제어 변수로 사용한 예제다.
char도 결국 증가 가능한 값이기 때문에 이런 반복이 가능하다.



반복 횟수만 중요한 for문

예제: ForTest2

for (int num = 1; num <= 10; num++) {
    rand = Math.random();
    System.out.println(rand);

    // 출력결과
    // 실행할 때마다 달라질 수 있음
}

예제: ForTest2_1

for (int num = 10; num > 0; num--) {
    rand = Math.random();
    System.out.println(rand);

    // 출력결과
    // 실행할 때마다 달라질 수 있음
}

두 코드는 겉모양은 다르지만 둘 다 10번 반복된다.

첫 번째는

  • 1부터 시작해서
  • 10까지 증가


    두 번째는
  • 10부터 시작해서
  • 1까지 감소

한다.

하지만 둘 다 반복문 안에서 num 자체를 따로 쓰지 않기 때문에, 중요한 것은 숫자 모양이 아니라 정확히 10번 반복한다는 사실이다.



예제: ForTest6

final char DECO = '*';
int count = (int)(Math.random() * 20);

for (int n = 0; n < count; n++)
    System.out.print(DECO);

// 출력결과
// 실행할 때마다 달라질 수 있음

이 코드는 count 값만큼 *을 출력한다.

  • count = 5면 5번
  • count = 12면 12번

반복한다.

즉, 이 경우에도 중요한 것은 몇 번 반복되는가이다.



헷갈리기 쉬운 부분

char는 문자처럼 보여도 내부적으로는 코드값을 가진 자료형이기 때문에 ++, 비교 연산, 범위 반복이 가능하다.

또 어떤 for문은 1부터 10까지처럼 값 자체가 중요하지만,
어떤 for문은 단지 몇 번 반복하느냐만 중요할 수도 있다.




5. 중첩 for문

개념

for문 안에 또 다른 for문이 들어가는 구조를 중첩 for문이라고 한다.
이 구조는 행과 열처럼 두 기준을 함께 반복해야 할 때 사용한다.

대표적인 예시는 아래와 같다.

  • 구구단 전체 출력
  • 별 찍기
  • 좌표 출력
  • 표 모양 출력

중요한 원리는 아주 단순하다.

  • 바깥쪽 for문은 큰 흐름을 담당한다.
  • 안쪽 for문은 바깥쪽이 한 번 돌 때마다 수행되는 작은 흐름을 담당한다.

즉, 바깥쪽이 한 번 돌 때마다 안쪽은 처음부터 끝까지 다시 돈다.



구구단 한 단 출력하기

예제: ForTest7

int dan = (int)(Math.random() * 9) + 1;

for (int num = 1; num <= 9; num++)
    System.out.print(dan + "x" + num + "=" + dan * num + "\t");

// 출력결과
// 실행할 때마다 달라질 수 있음
// 예: 4x1=4    4x2=8    4x3=12 ... 4x9=36

이 코드는 구구단 전체가 아니라, 난수로 뽑힌 특정 dan 하나만 출력한다.

예를 들어 dan = 4가 나왔다고 하면,

  • num = 1 → 4 x 1 = 4
  • num = 2 → 4 x 2 = 8
  • num = 3 → 4 x 3 = 12
  • ...
  • num = 9 → 4 x 9 = 36

이런 식으로 num만 바뀌면서 같은 단 안의 계산이 계속 이어진다.


즉, 여기서는

  • dan은 고정
  • num만 1부터 9까지 변함

이라는 흐름이다.



구구단 전체 출력하기

예제: ForTest9

for (int dan = 1; dan <= 9; dan++) {
    for (int num = 1; num <= 9; num++) {
        System.out.print(dan + "x" + num + "=" + dan * num + "\t");
    }
    System.out.println();
}
// 출력결과
// 1x1=1    1x2=2    ... 1x9=9
// 2x1=2    2x2=4    ... 2x9=18
// ...
// 9x1=9    9x2=18   ... 9x9=81

이제 구구단 전체가 훨씬 깔끔하게 출력된다.

데이터 흐름

처음 시작

  • dan = 1



안쪽 반복

  • num = 1 → 1 x 1 = 1
  • num = 2 → 1 x 2 = 2
  • ...
  • num = 9 → 1 x 9 = 9



안쪽 반복 종료

  • println() 실행 → 줄바꿈



그다음

  • dan = 2



안쪽 반복 다시 시작

  • num = 1 → 2 x 1 = 2
  • num = 2 → 2 x 2 = 4
  • ...
  • num = 9 → 2 x 9 = 18

이 흐름이 dan = 9까지 이어진다.

즉,

  • 바깥쪽 for문은 몇 단인지 바꾼다.
  • 안쪽 for문은 현재 단 안에서 1부터 9까지 곱한다.



print와 println 위치가 왜 중요한가

중첩 for문에서 가장 많이 헷갈리는 부분 중 하나가 print와 println의 위치다.

안쪽 반복문은 한 줄 안에서 값을 계속 이어서 출력해야 한다.
그래서 안쪽에서는 print를 쓴다.

바깥쪽 반복문이 한 번 끝났다는 것은 한 줄이 완성되었다는 뜻이다.
그래서 그때 줄을 바꾸기 위해 println()을 쓴다.


즉,

  • 안쪽 반복문: print
  • 바깥쪽 반복문 끝: println

이 구조가 기본이다.



별 찍기로 구조 이해하기

예제: ForTest10

final char DECO = '*';

for (int row = 1; row <= 10; row++) {
    for (int count = 1; count <= row; count++)
        System.out.print(DECO);
    System.out.println();
}

// 출력결과
// *
// **
// ***
// ****
// *****
// ******
// *******
// ********
// *********
// **********

이 코드는 삼각형 모양으로 별을 출력한다.

  • 바깥쪽 row는 줄 번호다.
  • 안쪽 count는 한 줄에 몇 개를 찍을지 결정하는 변수다.

첫 줄

  • row = 1
  • 안쪽 반복: count = 1까지만
  • 결과: *



둘째 줄

  • row = 2
  • 안쪽 반복: count = 1, 2
  • 결과: **



셋째 줄

  • row = 3
  • 안쪽 반복: count = 1, 2, 3
  • 결과: ***

즉, 현재 줄 번호만큼 별을 찍는 구조다.



헷갈리기 쉬운 부분

중첩 for문에서 가장 중요한 건
안쪽 반복문은 바깥쪽이 한 번 돌 때마다 처음부터 다시 시작한다는 점이다.

그래서 구구단 전체 출력은 9 x 9 = 81번 계산이 일어나고,
별 찍기에서는 줄이 바뀔 때마다 안쪽 반복 횟수가 다시 결정된다.




이름 붙은 반복문

개념

중첩 for문을 쓰다 보면, 안쪽 반복문만 끝내는 것이 아니라
바깥쪽 반복문까지 한 번에 끝내고 싶을 때가 있다.

그럴 때 사용하는 것이 이름 붙은 반복문이다.


반복문 앞에 unico:처럼 이름을 붙여 두면,
break unico;처럼 쓸 수 있다.

이렇게 하면 가장 가까운 반복문만 끝나는 것이 아니라,
이름이 붙은 반복문까지 한 번에 빠져나간다.


즉, 이름 붙은 반복문은
중첩 반복문에서 어디까지 종료할지 직접 지정하는 방법이라고 보면 된다.



코드 예제

예제: BreakTest2

unico:
for (int dan = 1; dan <= 9; dan++) {
    for (int num = 1; num <= 9; num++) {
        result = dan * num;
        if (result >= 30)
            break unico;
        System.out.print(dan + "x" + num + "=" + result + "\t");
    }
    System.out.println();
}

// 출력결과
// 1x1=1    1x2=2    ... 1x9=9
// 2x1=2    2x2=4    ... 2x9=18
// 3x1=3    3x2=6    ... 3x9=27
// 4x1=4    4x2=8    ... 4x7=28

이 코드는 구구단을 출력하다가, 곱한 결과가 30 이상이 되는 순간 반복을 멈춘다.

여기서 핵심은 break;가 아니라 break unico;를 썼다는 점이다.


unico는 바깥쪽 for문에 붙인 이름이다.
그래서 result >= 30이 되면 안쪽 반복문만 끝나는 것이 아니라,
바깥쪽 반복문도 함께 종료된다.



데이터 흐름

기본 구조는 중첩 for문과 같다.

  • 바깥쪽 반복문이 dan을 1부터 9까지 바꾼다.
  • 안쪽 반복문이 num을 1부터 9까지 바꾼다.
  • 두 값을 곱해서 구구단 한 줄을 만든다.

여기에 if (result >= 30) 조건이 추가되었다.


예를 들어 dan = 4일 때를 보면,

  • 4 x 7 = 28까지는 출력된다.
  • 다음 값인 4 x 8 = 32가 되면 조건이 참이 된다.
  • 이때 break unico;가 실행된다.
  • 그러면 안쪽 반복문만 끝나는 것이 아니라
  • unico라는 이름이 붙은 바깥 반복문까지 같이 종료된다.

그래서 다음 dan = 5로 넘어가지 않고,
전체 반복이 바로 끝난다.



헷갈리기 쉬운 부분

일반 break와 이름 붙은 break는 꼭 구분해서 봐야 한다.

  • break; → 가장 가까운 반복문만 종료
  • break 이름; → 지정한 이름의 반복문까지 종료

즉, 일반 break는 한 겹만 끊고,
이름 붙은 break는 바깥 반복문까지 한 번에 빠져나간다.


중첩 반복문에서는 이 차이를 알아야
왜 어떤 코드는 안쪽만 끝나고,
어떤 코드는 전체가 끝나는지 헷갈리지 않는다.




6. while문

개념

while문은 반복 횟수가 몇 번인지보다, 조건이 만족되는 동안 계속 반복할 때 잘 맞는 문법이다.

예를 들어

  • 합이 100 이상이 될 때까지 반복
  • 특정 값이 나올 때까지 계속 시도
  • 사용자가 종료할 때까지 입력 받기

같은 문제는 while문이 더 자연스럽다.

기본 문법은 아래와 같다.

while (조건식) {
    반복할 코드
}

while문은 괄호 안에 조건식이 반드시 들어가야 한다.
for문처럼 자리를 비워 둘 수 없기 때문에, 조건식이 없으면 에러가 난다.

또 while문은 먼저 조건을 검사한다.
그래서 처음부터 조건이 거짓이면, 한 번도 실행되지 않을 수 있다.



핵심 특징

while문은 괄호 안에 조건식만 들어간다.
즉, for문처럼 초기식, 조건식, 증감식을 한 줄에 같이 쓰는 구조가 아니다.

대신 보통

  • 초기식은 반복문 위쪽에서 미리 준비하고
  • 조건식은 while() 안에 쓰고
  • 증감식은 반복문 안쪽에서 직접 바꿔 준다

예를 들면 아래와 같다.

int i = 1;           // 초기식

while (i <= 10) {    // 조건식
    System.out.println(i);
    i++;             // 증감식
}

즉, while문도 흐름 자체는 for문과 같다.

  • 시작값 준비
  • 조건 검사
  • 코드 실행
  • 값 변화
  • 다시 조건 검사

다만 for문은 이것을 한 줄에 모아 쓰고,
while문은 그것을 밖과 안으로 나눠서 풀어 쓴 형태라고 보면 된다.

그래서 while문은 보통

  • 반복 횟수를 미리 딱 정하기 어려울 때
  • 몇 번 반복되는지보다 언제 조건이 거짓이 되는지가 중요할 때
  • 초기식과 증감식을 한 줄에 넣는 것보다 풀어서 쓰는 편이 더 자연스러울 때

많이 사용한다.



코드 예제

예제: WhileTest1

int sumV = 0;
int num;

while (sumV < 100) {
    num = (int)(Math.random() * 50) + 1;
    sumV += num;
    System.out.println("num : " + num + ", sumV : " + sumV);
}

// 출력결과
// 실행할 때마다 달라질 수 있음
// 예: num : 20, sumV : 20
//     num : 35, sumV : 55
//     num : 12, sumV : 67
//     ...

이 코드는 sumV가 100보다 작은 동안 계속 반복한다.
난수가 몇이 나올지 모르기 때문에 몇 번 반복될지도 미리 알 수 없다.

그래서 이런 문제는 for문보다 while문이 더 잘 어울린다.

데이터 흐름

시작 전

  • sumV = 0



첫 번째 반복

  • 조건 검사: 0 < 100 → 참
  • 난수 생성, 예를 들어 20
  • sumV += 20
  • 결과: sumV = 20



두 번째 반복

  • 조건 검사: 20 < 100 → 참
  • 난수 생성, 예를 들어 35
  • sumV += 35
  • 결과: sumV = 55



세 번째 반복

  • 조건 검사: 55 < 100 → 참
  • 난수 생성
  • 계속 누적

어느 순간 sumV가 100 이상이 되면 그 다음 조건 검사에서 거짓이 되어 종료된다.



for문과 while문 비교

아래 두 코드는 같은 뜻이다.

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

int i = 1;

while (i <= 10) {
    System.out.println(i);
    i++;
}

for문은 초기식, 조건식, 증감식을 한 줄에 모아서 쓴 것이고,
while문은 그것을 풀어 쓴 형태다.

즉, 두 문법은 완전히 다른 원리로 움직이는 것이 아니라,
같은 반복 흐름을 표현하는 방식이 다른 것에 가깝다.



헷갈리기 쉬운 부분

while문은 조건식이 반드시 필요하다.
그래서 괄호 안을 비워 두면 안 되고, 항상 참 또는 거짓을 판단할 수 있는 식이 들어가야 한다.

또 while문에서는 초기식과 증감식을 자동으로 처리해 주지 않는다.
그래서 값을 바꿔야 하는 반복이라면, 반복문 밖과 안에서 직접 써줘야 한다.

이 부분을 놓치면 값이 바뀌지 않아서 조건이 계속 참으로 남고, 의도하지 않은 무한 반복이 될 수 있다.

즉, while문은 몇 번 도는지가 아니라 언제 조건이 거짓이 되는지가 중요하다.
횟수보다 조건이 중심인 반복문이라고 이해하면 된다.




7. break와 continue

개념

반복문은 보통 조건이 거짓이 되면 끝난다.
하지만 실제 코드에서는 중간에 반복을 강제로 끝내거나, 이번 차례만 건너뛰고 다음 반복으로 넘어가야 할 때가 있다.

그때 사용하는 문장이 break와 continue다.

  • break → 반복 자체를 끝낸다.
  • continue → 이번 반복만 끝내고 다음 차례로 넘어간다.



무한 루프와 break

조건이 항상 참이면 반복은 끝나지 않는다.
이런 반복을 무한 루프라고 한다.

대표적인 형태는 아래 두 가지다.

for (;;) {
    // 반복 코드
}

while (true) {
    // 반복 코드
}

문법상 둘 다 가능하지만, 보통은 while(true)가 더 읽기 쉽다.

이때는 반복문 안에서 빠져나오는 장치가 필요하다.
그때 사용하는 문법이 break다.



break문

예제: WhileTest2

int lottoNum;

while (true) {
    lottoNum = (int)(Math.random() * 6) + 1;
    if (lottoNum == 3) {
        System.out.println("당첨!! ㅋㅋㅋ : " + lottoNum);
        break;
    } else {
        System.out.println("재시도!! ㅠㅠㅠ : " + lottoNum);
    }
}

System.out.println("수행종료...");

// 출력결과
// 실행할 때마다 달라질 수 있음
// 예: 재시도!! ㅠㅠㅠ : 5
//     재시도!! ㅠㅠㅠ : 1
//     당첨!! ㅋㅋㅋ : 3
//     수행종료...

이 코드는 3이 나올 때까지 계속 반복한다.
3이 나오게 되면 while문 안에 있는if문 실행되면서 당첨!! ㅋㅋㅋ : 3하고 끝이난다. => 끝이나는 이유는 break 때문이다.
3이 나오지 않으면 else문이 실행되면서 재시도!! ㅠㅠㅠ : ?이 나오고 다시 반복된다.



break는 가장 가까운 반복문 하나만 끝낸다

예제: BreakTest1

for (int dan = 1; dan <= 9; dan++) {
    for (int num = 1; num <= 9; num++) {
        result = dan * num;
        if (result >= 30)
            break;
        System.out.print(dan + "x" + num + "=" + result + "\t");
    }
    System.out.println();
}

// 출력결과
// 1x1=1    1x2=2    ... 1x9=9
// 2x1=2    2x2=4    ... 2x9=18
// 3x1=3    3x2=6    ... 3x9=27
// 4x1=4    4x2=8    ... 4x7=28
// 5x1=5    5x2=10   ... 5x5=25
// ...

이 코드는 result가 30 이상이 되면 break를 실행한다.
여기서 중요한 점은 break가 안쪽 for문만 끝낸다는 것이다.

데이터 흐름

기본 반복 구조는 앞에서 본 구구단 전체 출력과 같다.
바깥쪽 반복문이 dan을 바꾸고, 안쪽 반복문이 num을 1부터 9까지 바꾸며 곱셈을 진행한다.

여기서는 그 흐름에 if (result >= 30) 조건이 추가되었다.
즉, 곱한 결과가 30 이상이 되는 순간 break가 실행되어 반복이 중간에서 끊긴다.

예를 들어 dan = 4일 때

  • 4 x 7 = 28까지는 출력된다.
  • 4 x 8 = 32가 되면 break가 실행된다.
  • 그러면 안쪽 반복문만 끝난다.
  • 바깥쪽 반복문은 계속 돌아서 다음 dan = 5로 넘어간다.

즉, 일반 break는 현재 가장 안쪽에 있는 반복문 하나만 종료한다.



라벨 break로 바깥 반복문까지 끝내기

예제: BreakTest2

unico:
for (int dan = 1; dan <= 9; dan++) {
    for (int num = 1; num <= 9; num++) {
        result = dan * num;
        if (result >= 30)
            break unico;
        System.out.print(dan + "x" + num + "=" + result + "\t");
    }
    System.out.println();
}

// 출력결과
// 1x1=1    1x2=2    ... 1x9=9
// 2x1=2    2x2=4    ... 2x9=18
// 3x1=3    3x2=6    ... 3x9=27
// 4x1=4    4x2=8    ... 4x7=28

이번에는 unico:라는 이름을 바깥 반복문에 붙였다.
그리고 break unico;를 사용했다.

이렇게 하면 안쪽 반복문만 끝나는 것이 아니라, 이름이 붙은 바깥 반복문까지 한 번에 빠져나간다.

데이터 흐름

기본 반복 구조는 앞의 예제와 같다.
바깥쪽 반복문이 dan을 바꾸고, 안쪽 반복문이 num을 1부터 9까지 바꾸며 곱셈을 진행한다.

여기서는 그 흐름에 break unico;가 추가되었다.
unico는 바깥 반복문에 붙인 이름이기 때문에, 조건이 맞으면 안쪽 반복문만이 아니라 이름이 붙은 바깥 반복문까지 함께 종료된다.

예를 들어 dan = 4일 때

  • 4 x 7 = 28까지는 출력된다.
  • 4 x 8 = 32가 되면 break unico;가 실행된다.
  • 그러면 안쪽 반복문이 끝나고
  • 바깥쪽 반복문도 바로 끝난다.
  • 그래서 다음 dan = 5로 넘어가지 않고 전체 반복이 종료된다.

즉, break 이름;은 지정한 위치의 반복문까지 한 번에 빠져나가는 방식이다.



헷갈리기 쉬운 부분

정리하면 아래와 같다.

  • break; → 가장 가까운 반복문만 종료
  • break 이름; → 지정한 바깥 반복문까지 종료

즉, 일반 break는 한 겹만 끊고,
라벨 break는 이름이 붙은 위치까지 한 번에 빠져나간다.



continue문

예제: ContinueTest

int num;

while (true) {
    num = (int)(Math.random() * 31); // 0~30

    if (num == 0) {
        System.out.println("\n종료");
        break;
    }

    if (num > 26) {
        System.out.println('@');
        continue;
    }

    System.out.printf("%d(%c)", num, 96 + num);
}

// 출력결과
// 실행할 때마다 달라질 수 있음
// 예: 5(e)12(l)
//     @
//     3(c)
//     종료

이 코드는 난수를 계속 뽑다가

  • 0이면 종료
  • 27~30이면 @ 출력 후 다음 반복으로 이동
  • 그 외에는 숫자와 문자를 함께 출력

하는 구조다.

여기서 핵심은 continue가 실행되면 현재 반복에서 아래에 남아 있는 코드를 더 이상 실행하지 않고, 바로 다음 반복으로 넘어간다는 점이다.

예를 들어 num = 28이 나왔다고 하면

  • num == 0 → 거짓
  • num > 26 → 참
  • @ 출력
  • continue 실행
  • 아래 System.out.printf("%d(%c)", num, 96 + num); 는 실행되지 않음
  • 다음 반복으로 바로 넘어감

즉, continue는 반복문 전체를 끝내는 것이 아니라,
이번 차례만 여기서 멈추고 다음 차례로 넘어가게 만든다.



break와 continue를 같이 보면

예제: BreakContinueTest2

while (true) {
    System.out.print("양의 숫자를 입력하숑 : ");
    num = input.nextInt();

    if (num == 0) {
        break;
    } else if (num < 0) {
        System.out.println("양수를 입력하지 않아서 다시 입력!!");
        continue;
    } else {
        System.out.println("입력된 숫자 --> " + num);
    }

    factNum = 1;
    for (int i = 1; i <= num; i++)
        factNum *= i;

    System.out.println(num + "! --> " + factNum);
}

// 출력결과
// 실행할 때마다 입력에 따라 달라짐

이 코드는 break와 continue 차이를 한 번에 보여준다.

  • 0 입력 → break → 반복문 전체 종료
  • 음수 입력 → continue → 현재 반복의 남은 코드를 건너뛰고 다시 입력 받기
  • 양수 입력 → 계속 진행 → 팩토리얼 계산

예를 들어 num = -3이면

  • num == 0 → 거짓
  • num < 0 → 참
  • "양수를 입력하지 않아서 다시 입력!!" 출력
  • continue 실행
  • 아래 팩토리얼 계산 코드는 실행되지 않음
  • 다음 입력 반복으로 바로 넘어감

여기서 중요한 점은 자신이 들어 있는 반복문에서 현재 차례의 남은 코드 전체를 건너뛴다는 것이다.

즉, 아래 코드는 전부 실행되지 않는다.

factNum = 1;
for (int i = 1; i <= num; i++)
    factNum *= i;

System.out.println(num + "! --> " + factNum);



좋아.
printf는 개념만 적으면 좀 붕 뜨니까, 실제로 어떻게 쓰는지 바로 보이는 예제까지 포함해서 이렇게 마무리하면 된다. 제공한 PrintfTest1.java 예제를 기준으로 다듬은 버전이다.


참고: printf

개념

print, println은 값을 단순하게 출력할 때 편하다.
하지만 숫자, 문자열, 문자, 실수 등을 형식에 맞춰 보기 좋게 출력하려면 printf를 사용한다.

즉,

  • print → 줄바꿈 없이 출력
  • println → 출력 후 줄바꿈
  • printf → 형식을 지정해서 출력

이라고 보면 된다.



핵심 특징

printf는 포맷 문자를 사용해서 출력 모양을 정한다.
자주 쓰는 형식은 아래와 같다.

  • %d : 정수
  • %f : 실수
  • %c : 문자
  • %s : 문자열
  • %b : 논리값
  • %x : 16진수
  • %o : 8진수
  • %e : 지수 형태 실수
  • %n : 줄바꿈



코드 예제

예제: PrintfTest1

System.out.printf("테스트입니당%n");
System.out.printf("테스트%d입니당\n", 10);
System.out.printf("%d %x %o %c\n", 100, 100, 100, 100);
System.out.printf("%d %1$x %1$o %1$c\n", 100);
System.out.printf("%c %c %c %c\n", '가', 'A', '!', '3');
System.out.printf("%b\n", true);
System.out.printf("%f %e\n", 100.0, 100.0);
System.out.printf("%.2f\n", 123.5678);
System.out.printf("%,d원\n", 1000000);

// 출력결과
// 테스트입니당
// 테스트10입니당
// 100 64 144 d
// 100 64 144 d
// 가 A ! 3
// true
// 100.000000 1.000000e+02
// 123.57
// 1,000,000원

이 예제는 printf에서 자주 쓰는 형식을 한 번에 보여준다.
같은 값 100도 %d, %x, %o, %c로 출력하면 각각 10진수, 16진수, 8진수, 문자로 다르게 보인다. 또 %.2f는 실수를 소수 둘째 자리까지 보여주고, %,d는 큰 숫자에 쉼표를 넣어서 읽기 쉽게 출력한다.



형식이 적용되는 방식

예를 들어 아래 코드를 보면

System.out.printf("%d %x %o %c\n", 100, 100, 100, 100);

같은 값 100을 서로 다른 형식으로 출력한다.

  • %d → 100
  • %x → 64
  • %o → 144
  • %c → d

즉, 값 자체가 바뀌는 것이 아니라 출력 형식만 달라지는 것이다.


또 아래 코드를 보면

System.out.printf("%.2f\n", 123.5678);

%.2f는 실수를 소수 둘째 자리까지 출력하라는 뜻이다.
그래서 결과는 123.57이 된다. 이것도 값이 바뀌는 것이 아니라, 보여주는 모양만 바뀌는 것이다.



같은 값을 여러 형식에 다시 쓰기

아래 코드는 데이터가 하나만 들어가지만, 그 값을 여러 형식으로 다시 사용한다.

System.out.printf("%d %1$x %1$o %1$c\n", 100);

여기서 %1$x, %1$o, %1$c의 1$는 첫 번째 데이터인 100을 다시 쓰겠다는 뜻이다.
그래서 값 하나로도 여러 형식 출력을 만들 수 있다.



헷갈리기 쉬운 부분

printf는 println처럼 자동 줄바꿈이 되지 않는다.
그래서 \n이나 %n을 직접 넣어야 줄이 바뀐다. 예제에서도 %n과 \n이 둘 다 사용된다.

또 포맷 문자의 개수와 뒤에 넣는 데이터 개수는 맞아야 한다.
예를 들어 %d %x %o %c처럼 포맷 문자가 4개면, 그에 맞는 데이터도 4개가 필요하다.

그리고 가장 중요한 점은, printf는 값을 바꾸는 문법이 아니라 출력 모양을 바꾸는 문법이라는 점이다.
즉, 계산을 하는 문법이 아니라 결과를 보기 좋게 보여주는 출력 문법으로 이해하면 된다.

0개의 댓글