자바 반복문 완전 정복 — for/while/do-while, 향상된 for, break/continue/라벨
목차
- [개념 요약]
- [예제 코드]
- [동작 원리]
- [요약]
개념 요약
- 반복문(Loop): 조건이 참인 동안 코드를 여러 번 실행하는 구문. 핵심은 반복 변수(initialization), 종료 조건(condition), 증감(step) 이야.
- 종류:
for(전통식),while,do-while, 향상된 for(Enhanced for-each). 전통식for/while은 사전 검사(pre-check),do-while은 사후 검사(post-check). - 제어 구문(Control Flow):
break(반복 탈출),continue(다음 반복으로 건너뜀), 라벨(label) 을 붙여 중첩 루프에서 바깥 루프까지 한 번에 탈출/건너뛰기 가능. - 컬렉션과 반복: 배열/
Iterable은 향상된 for로 간결하게 순회. 삭제/수정이 필요하면Iterator의remove()또는removeIf를 써. - 오류 예방: 오프바이원(Off-by-one), 무한 루프, ConcurrentModificationException 을 특히 조심. 종료 조건과 증감, 컬렉션 수정 시점을 명확히 해.
왜 중요한가?
반복문은 데이터 처리·검증·검색의 기본 도구야. 올바른 구문 선택과 종료 조건 설계만으로 성능·가독성·안정성 을 한 번에 챙길 수 있어.
반복문 비교 요약
| 구문 | 검사 시점 | 전형적 형태 | 주 사용처 | 비고 |
|---|---|---|---|---|
for |
사전 | for (init; cond; step) |
인덱스 기반 순회, 범위 제어 | 인덱스/step 제어가 쉬움 |
while |
사전 | while (cond) |
조건이 먼저인 루프 | 입력/상태 기반 반복 |
do-while |
사후 | do { ... } while (cond); |
최소 1회 실행 보장 | 메뉴/재시도 로직 |
| 향상된 for | 사전 | for (T e : iterable) |
배열/컬렉션 순회 | 인덱스/삭제가 필요하면 부적합 |
팁: 읽는 사람이 바로 의도를 파악할 수 있는 구문을 고르자. 인덱스·범위 제어가 핵심이면 전통식 for, 요소만 훑으면 향상된 for가 좋아.
예제 코드
1) 기본 순회 + 제어 구문 한 번에 보기
import java.util.*;
public class LoopBasics {
public static void main(String[] args) {
int[] nums = {3, -1, 7, 0, 9};
int sum = 0;
// 전통식 for: 인덱스로 접근, 음수는 건너뛰기(continue)
for (int i = 0; i < nums.length; i++) {
if (nums[i] < 0) continue;
sum += nums[i];
}
System.out.println("sum = " + sum); // 19
// 향상된 for: 요소만 쓰면 가장 간단
String[] names = {"kim", "lee", "park"};
for (String n : names) {
System.out.println(n.toUpperCase());
}
// while: 조건 우선 — 첫 번째 0의 인덱스 찾기
int i = 0;
while (i < nums.length && nums[i] != 0) i++;
System.out.println("first zero index = " + i); // 3
// do-while: 최소 한 번 실행 보장(재시도 시나리오 등)
int attempts = 0;
do { attempts++; } while (attempts < 1);
System.out.println("attempts = " + attempts); // 1
// 중첩 루프 + 라벨: 합이 12인 쌍 찾으면 바깥 루프까지 탈출
int target = 12;
outer:
for (int a : nums) {
for (int b : nums) {
if (a + b == target) {
System.out.println(a + " + " + b + " = " + target);
break outer; // 바깥(outer) 루프 탈출
}
}
}
}
}2) 컬렉션 수정은 이렇게: Iterator / removeIf
import java.util.*;
public class SafeRemove {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
// 1) Iterator.remove() — 순회하면서 안전하게 삭제
for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
if (it.next() % 2 == 1) it.remove(); // 홀수 삭제
}
System.out.println(list); // [2, 4]
// 2) Java 8+: 조건부 일괄 삭제
list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
list.removeIf(x -> x % 2 == 1);
System.out.println(list); // [2, 4]
}
}동작 원리
- 사전/사후 검사:
for/while은 조건을 먼저 평가해 0회 실행 가능,do-while은 블록을 먼저 실행 후 조건 검사로 최소 1회 실행을 보장해. - 향상된 for의 내부: 컴파일되면
Iterator를 사용해hasNext()/next()로 순회해. 그래서 인덱스 접근이나 요소 삭제에 맞지 않고, 삭제는Iterator.remove()로 해야 안전해. - 제어 구문:
break는 현재 루프를 종료,continue는 다음 반복으로 점프. 라벨을 붙이면 다중 루프에서 바깥 루프까지 한 번에 탈출/건너뛰기가 가능하지만, 남용 시 가독성을 해친다. - 시간 복잡도: 반복 횟수에 비례. 단일 루프는 보통
O(n), 중첩 루프는O(n^2)등. 필요 이상 중첩을 피하고, 조기 종료(break)를 적극 활용하자. - 안전 장치: 종료 조건이 바뀌지 않으면 무한 루프가 생겨. 증감/상태 변경이 반드시 일어나도록 코드를 검토하고, 빠른 실패(예: 범위·널 체크)를 앞단에 두자.
대안과 선택 기준
- Stream API: 필터·매핑 등 선언형 처리가 필요하면
stream().filter(...).map(...)→collect(...). 조기 종료는anyMatch/findFirst로, 인덱스 의존 로직은 전통식for가 더 명확해. - 인덱스가 필요 없을 때: 향상된 for로 간결하게. 단, 요소 삭제가 필요하면
Iterator/removeIf를 사용. - 중첩 루프 탈출: 가능하면 함수를 분리하거나
return으로 구조를 단순화. 라벨은 마지막 수단으로 생각해.
요약
- 자바 반복문은
for/while/do-while/향상된 for로 나뉘고, 검사 시점과 의도에 맞춰 고르면 돼. - 컬렉션 순회는 향상된 for가 깔끔하지만, 삭제/수정은
Iterator.remove()또는removeIf가 안전해. break/continue는 흐름 제어에 유용하고, 라벨은 중첩 루프 탈출에만 최소한으로 사용하자.- 무한 루프·오프바이원·ConcurrentModificationException을 조심하고, 필요 시 조기 종료로 효율을 끌어올리자.
- 이어서 보면 좋은 주제: Java Stream/Collector, Iterator와 Iterable 심화.
'Backend > Java' 카테고리의 다른 글
| [JAVA] 예외처리 (0) | 2025.09.22 |
|---|---|
| [JAVA] 클래스 (0) | 2025.09.15 |
| [JAVA] 변수 (0) | 2025.09.08 |
| [Java] 기본형 vs 참조형 (1) | 2025.02.11 |
| 스파르타 코딩 클럽 SQL 1주차 (0) | 2022.06.28 |