for와 중첩 반복
카운터의 초기화·조건·증가를 한곳에 모으고 중첩 반복의 총 실행 횟수와 for·while 선택 기준을 계산합니다.
while로 모든 반복을 표현할 수 있지만 반복 횟수를 세는 변수의 선언, 계속 조건, 증감이 멀리 떨어질 수 있습니다.
for는 이 세 요소를 머리 부분에 모아 범위를 보여 줍니다.
먼저 배열 없이 1부터 3까지 출력하며 문법을 익힌 뒤, 실행 인자를 순회하는 형태로 확장합니다.
FLOWCHART · ITERATION ORDER
for 한 회차의 실행 순서와 카운터 수명
초기화는 한 번만 실행된다. 이후에는 조건이 참인 동안 본문과 증가가 이어지고, 조건이 거짓이 되는 순간 반복 블록과 카운터의 접근 범위가 함께 끝난다.
한 번 초기화한 뒤 조건 → 본문 → 증가 → 조건 순서로 반복합니다.
초기화 · 한 번
int memberNumber = 1을 for에 들어갈 때 한 번만 실행합니다.조건 · 본문보다 먼저
memberNumber <= 3이 참일 때만 본문으로 갑니다. 첫 검사부터 거짓이면 본문과 증가는 0회입니다.본문 · 1, 2, 3 출력
각 회차의 현재
memberNumber를 출력합니다.증가 · 다시 조건으로
memberNumber++로 2, 3, 4를 만든 뒤 같은 조건을 재검사합니다.종료 · 4에서 false
조건이 거짓이면 반복을 끝냅니다. for 헤더에서 선언한 카운터는 헤더와 반복 블록 안에서만 접근할 수 있습니다.
- 안쪽
- for 헤더의 조건·증가와 반복 본문에서
memberNumber를 사용할 수 있습니다. - 종료 뒤
- 반복 블록을 벗어나면
memberNumber는 스코프 밖이라 접근할 수 없습니다.
- true이면 본문으로
- false이면 즉시 종료
- 카운터 접근 가능 범위
결과가 1, 2, 3인 까닭은 증가가 본문 뒤에 오고, 4가 된 뒤 조건을 한 번 더 검사하기 때문이다.
가장 작은 for
다음 반복문은 회차 1, 2, 3을 차례로 출력합니다.
public class ForRange {
public static void main(String[] args) {
for (int memberNumber = 1; memberNumber <= 3; memberNumber++) {
System.out.println("member=" + memberNumber);
}
}
}member=1
member=2
member=3초기값은 1, 계속 조건은 memberNumber <= 3, 한 회차 뒤의 변화는 memberNumber++입니다.
배열의 0 기반 인덱스와 길이 경계는 ch3에서 배열을 만든 뒤 다룹니다.
for문의 실행 순서
for (int memberNumber = 1; memberNumber <= 3; memberNumber++) {
System.out.println(memberNumber);
}실행 순서는 다음과 같습니다.
int memberNumber = 1은 반복 전체에서 한 번 실행됩니다.memberNumber <= 3을 검사합니다. 거짓이면 반복을 끝냅니다.- 본문을 실행합니다.
memberNumber++를 실행합니다.- 2번 조건 검사로 돌아갑니다.
같은 뜻의 while은 카운터 선언이 반복문 밖에 남습니다.
int memberNumber = 1;
while (memberNumber <= 3) {
System.out.println(memberNumber);
memberNumber++;
}카운터가 반복 밖에서 필요 없다면 for가 스코프를 더 좁힙니다.
반대로 종료 시점이 사용자 명령이나 누적 합계처럼 본문 사건에 달려 있으면 while이 읽기 쉽습니다.
생략식과 무한 반복
for의 초기화, 조건, 증감은 각각 생략할 수 있습니다.
for (;;) {
// break가 없다면 계속 실행
}조건을 생략하면 항상 참으로 취급합니다.
while (true)와 같은 무한 반복입니다.
종료 조건이 본문 안의 여러 사건으로 표현될 때 사용할 수 있지만 break가 없거나 도달할 수 없으면 끝나지 않습니다.
다음 프로그램은 명시적인 한계에서 빠져나옵니다.
public final class ForWithBreak {
public static void main(String[] args) {
int sum = 0;
for (int number = 1; ; number++) {
sum += number;
if (sum >= 15) {
System.out.println("number=" + number);
break;
}
}
System.out.println("sum=" + sum);
}
}number=5
sum=15number 초기화와 증가는 for 머리에 있고, 합계라는 종료 사건은 본문에 있습니다.
조건 칸을 비운 이유를 break가 직접 보여 줍니다.
단순히 number <= 5처럼 상한을 알고 있다면 조건 칸에 쓰는 편이 낫습니다.
중첩 반복 횟수
회원가입 요청 2개 묶음에서 각 묶음의 3개 슬롯을 출력합니다.
public final class MemberGrid {
public static void main(String[] args) {
int printed = 0;
for (int batch = 1; batch <= 2; batch++) {
for (int slot = 1; slot <= 3; slot++) {
printed++;
System.out.println("batch=" + batch + ", slot=" + slot);
}
}
System.out.println("printed=" + printed);
}
}batch=1, slot=1
batch=1, slot=2
batch=1, slot=3
batch=2, slot=1
batch=2, slot=2
batch=2, slot=3
printed=6바깥 반복 한 회마다 안쪽 반복이 처음부터 세 번 실행됩니다.
총 본문 횟수는 2 × 3 = 6입니다.
두 상한이 입력 크기라면 작업량도 곱으로 늘어납니다.
격자나 모든 조합이 실제 요구일 때만 중첩합니다.
안쪽에서 break하면 현재 batch의 slot 반복만 끝나고 다음 batch로 넘어갑니다.
전체 반복을 끝내려면 바깥 상태를 함께 바꾸거나 메서드에서 return하는 구조를 고려합니다.
SEMANTIC TABLE · NESTED ITERATION
중첩 for의 2×3 실행 순서와 제어 범위
행은 바깥 batch, 열은 그 안의 slot이다. 두 행과 세 열의 교차점이 정확히 여섯 번 실행되며, 안쪽 continue와 break는 현재 안쪽 반복만 제어한다.
| 바깥 반복 · batch | 안쪽 slot 1 | 안쪽 slot 2 | 안쪽 slot 3 |
|---|---|---|---|
| batch 1 | 전체 순서 1 · (1, 1) |
전체 순서 2 · (1, 2) |
전체 순서 3 · (1, 3) |
| batch 2 | 전체 순서 4 · (2, 1) |
전체 순서 5 · (2, 2) |
전체 순서 6 · (2, 3) |
- 2 × 3 = 6회
- 바깥 반복 2회마다 안쪽 반복 3회가 완주하면 본문은 모두 6회 실행됩니다.
- 안쪽 continue
- 현재 slot의 남은 본문만 건너뛰고 같은 batch의 다음 slot으로 갑니다.
- 안쪽 break
- 현재 batch의 남은 slot을 끝내고 바깥 for의 다음 batch로 갑니다.
2 batch × 3 slot 본문 실행은 전체 6회입니다.
batch 1 · 전체 순서 1–3
- slot 1
(1, 1)· 전체 순서 1 - slot 2
(1, 2)· 전체 순서 2 - slot 3
(1, 3)· 전체 순서 3
batch 2 · 전체 순서 4–6
- slot 1
(2, 1)· 전체 순서 4 - slot 2
(2, 2)· 전체 순서 5 - slot 3
(2, 3)· 전체 순서 6
- 안쪽 continue
- 현재 slot의 나머지만 건너뛰며 같은 batch의 다음 slot은 계속 실행합니다.
- 안쪽 break
- 현재 batch의 안쪽 for만 끝내며 바깥 for는 다음 batch를 시작합니다.
행 header가 바깥 batch를, 열 header가 그 안의 slot을 나타낸다. 제어문 앞의 “안쪽”이 어느 반복을 건너뛰거나 끝내는지 결정한다.
for 기반 일괄 처리
앞 절의 while 배치는 index가 항상 증가하는지 따로 확인해야 했습니다.
모든 토큰을 한 번씩 보는 현재 요구에는 향상된 for가 더 직접적입니다.
for (String token : args)는 args의 각 문자열을 앞에서부터 한 번씩 token에 넣는 향상된 for입니다.
ch1에서 args가 문자열 배열임을 확인했고, 배열의 생성과 인덱스는 다음 장에서 자세히 배웁니다.
여기서는 카운터가 필요 없는 “각 입력 한 번”의 표현으로 사용합니다.
나이 부분은 이 절에서 정수 문자열이라고 가정하며, 숫자 형식이나 int 범위 초과 복구는 ch3에서 다룹니다.
public final class BatchFor {
public static void main(String[] args) {
int savedCount = 0;
int totalAge = 0;
for (String token : args) {
if (token.equals("quit")) {
break;
}
int separator = token.indexOf(':');
if (separator <= 0 || separator == token.length() - 1) {
System.out.println("skip=" + token);
continue;
}
String email = token.substring(0, separator);
int age = Integer.parseInt(token.substring(separator + 1));
if (age < 14 || age > 120) {
System.out.println("skip=" + token);
continue;
}
savedCount++;
totalAge += age;
System.out.println("saved=" + email);
}
System.out.println("count=" + savedCount + ", total=" + totalAge);
}
}saved=variables
skip=invalid
saved=conditions
count=2, total=75화면 번호나 이전 원소 위치가 필요하다면 인덱스 for를 사용합니다.
for와 while 선택
| 반복 요구 | 우선 선택 | 카운터 범위 |
|---|---|---|
| 0부터 배열 길이 전까지 | 인덱스 for | for 블록 내부 |
| 각 입력을 한 번씩 | 향상된 for | 카운터 없음 |
| 종료 명령까지 | while | 입력 상태에 따라 |
| 합계가 한계를 넘을 때까지 | while 또는 무한 for + break | 본문 사건에 따라 |
| 행×열 모든 조합 | 중첩 for | 각 블록에 별도 카운터 |
문법을 서로 변환할 수 있다는 사실보다 종료 조건이 어디에 가장 분명히 보이는지를 기준으로 삼습니다.
반복 변수의 수명을 좁힐 수 있다면 그것도 선택 근거입니다.
연습 문제
5개 가입 요청 묶음마다 3개의 처리 슬롯을 중첩 for로 출력하세요.
단, 세 번째 묶음의 두 번째 슬롯은 점검 중이라 continue로 건너뛰고, 총 출력 슬롯 수를 마지막에 표시합니다.
해설 보기
public final class SignupSlots {
public static void main(String[] args) {
int printed = 0;
for (int batch = 1; batch <= 5; batch++) {
for (int slot = 1; slot <= 3; slot++) {
if (batch == 3 && slot == 2) {
continue;
}
printed++;
System.out.println(batch + "-" + slot);
}
}
System.out.println("printed=" + printed);
}
}전체 조합은 15개이고 하나를 건너뛰므로 printed=14입니다.
continue는 안쪽 slot 반복의 현재 회차만 끝내며 세 번째 묶음의 세 번째 슬롯과 이후 묶음은 계속 실행됩니다.