Day04: 반복문
안녕하세요! 여러분의 Java 가이드, 홍순구 튜터입니다.
Day 4에 오신 걸 환영합니다!
지난 시간에 우리는 연산자로 계산하고, 조건문으로 상황에 따라 다르게 동작하는 프로그램을 만들었어요.
if/else로 팔로워 등급을 판정하고, switch 표현식으로 알림 메시지를 깔끔하게 분기했죠.
그런데 마지막에 아쉬운 문제가 하나 남았습니다.
팔로워 5명의 이름을 출력하려면 System.out.println()을 5번 복사해야 했어요.
50명이면? 50번 복사.
1,000명이면? 1,000번 복사.
이건 사람이 할 일이 아닙니다. 컴퓨터가 가장 잘하는 일은 바로 같은 작업을 빠르게 반복하는 것이에요. 오늘은 그 힘을 빌려봅시다!
🎯 학습 목표
for문으로 정해진 횟수만큼 반복할 수 있다while/do-while로 조건에 따라 반복할 수 있다break/continue로 반복 흐름을 제어할 수 있다enhanced for로 배열을 간결하게 순회할 수 있다- 중첩 반복으로 2차원 데이터(표, 그래프, 그리드)를 출력할 수 있다
Step 1: "복사의 악순환을 끝내자" — for 루프의 등장
지난 시간 마무리에서 이런 코드를 봤어요.
System.out.println("팔로워 1번째 출력");
System.out.println("팔로워 2번째 출력");
System.out.println("팔로워 3번째 출력");
System.out.println("팔로워 4번째 출력");
System.out.println("팔로워 5번째 출력");
5줄이면 그래도 견딜 만합니다. 그런데 팔로워가 50명이면? 같은 코드를 50번 복사해야 해요. 오타가 나면 찾기도 어렵고, 수정할 때 50군데를 다 고쳐야 합니다.
이 문제를 해결하는 게 반복문(Loop) 입니다. 가장 먼저 만날 반복문은 for 입니다.
for 문의 구조
for (int i = 1; i <= 5; i++) {
System.out.println("팔로워 " + i + "번째 출력");
}
한 줄로 5번을 반복합니다! 괄호 안에 세 가지 요소가 들어가요.
| 요소 | 역할 | 예시 |
|---|---|---|
| 초기값 | 카운터 변수를 만들고 시작값을 정한다 | int i = 1 |
| 조건 | 이 조건이 true인 동안 반복한다 |
i <= 5 |
| 증감 | 한 바퀴 돌 때마다 카운터를 변화시킨다 | i++ |
세미콜론(;)으로 구분한다는 것만 기억하면 돼요.
for (시작; 조건; 변화) — 이 세 박자가 반복의 전부입니다.
실행해 봅시다
// day04/ForLoopBasics.java
void main() {
for (int i = 1; i <= 5; i++) {
System.out.println("팔로워 " + i + "번째 출력");
}
}
팔로워 1번째 출력
팔로워 2번째 출력
팔로워 3번째 출력
팔로워 4번째 출력
팔로워 5번째 출력
5줄짜리 복사 코드가 3줄로 줄었어요.
50명이어도 i <= 50으로 바꾸기만 하면 됩니다.
숫자 합계 구하기
for 루프는 "세면서 반복"하는 데 딱이에요. 1부터 10까지의 합계를 구해 봅시다.
void main() {
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum = sum + i;
}
System.out.println("합계: " + sum);
}
합계: 55
sum이라는 변수에 1, 2, 3, ... 10을 차례로 더합니다.
루프가 끝나면 sum에 55가 담겨 있어요.
카운트다운도 가능합니다
증감 부분에 i--를 쓰면 거꾸로 셀 수 있어요.
void main() {
for (int sec = 5; sec >= 1; sec--) {
System.out.println(sec + "초 후 스토리가 사라집니다...");
}
System.out.println("스토리가 삭제되었습니다!");
}
5초 후 스토리가 사라집니다...
4초 후 스토리가 사라집니다...
...
1초 후 스토리가 사라집니다...
스토리가 삭제되었습니다!
🙋 학생 질문 — "i 대신 다른 이름을 써도 되나요?"
네, 어떤 이름이든 괜찮아요.
i는 index의 약자로 관례적으로 많이 쓰지만, count, num, step 등 의미에 맞는 이름을 써도 됩니다.
위의 카운트다운 예제에서도 sec(second)을 썼죠.
중요한 건 내가 읽었을 때 무슨 뜻인지 알 수 있는 이름이에요.
Step 2: "조건에 따라 반복하기" — while과 do-while
for 루프는 "몇 번 반복할지 미리 아는 상황"에 딱 맞습니다. 그런데 몇 번 돌아야 끝날지 모를 때는 어떻게 할까요?
예를 들어, 팔로워가 100명인 계정이 매주 2배씩 성장한다고 해봐요. 1만 명을 넘으려면 몇 주가 걸릴까요? 미리 계산하지 않으면 모릅니다.
이런 상황에서 while 루프를 씁니다.
while — "조건이 참인 동안 반복"
// day04/WhileAndDoWhileLoops.java
void main() {
int followers = 100;
int weeks = 0;
while (followers < 10000) {
followers = followers * 2;
weeks++;
System.out.println(weeks + "주차: 팔로워 " + followers + "명");
}
System.out.println("1만 돌파까지 " + weeks + "주 걸렸습니다!");
}
1주차: 팔로워 200명
2주차: 팔로워 400명
3주차: 팔로워 800명
...
7주차: 팔로워 12800명
1만 돌파까지 7주 걸렸습니다!
while 뒤의 괄호에 조건만 넣으면 됩니다.
for 처럼 세 박자로 나눌 필요가 없어서, "조건만 중요한 상황"에서 깔끔해요.
do-while — "최소 한 번은 실행"
while과 비슷하지만 순서가 다릅니다. while은 조건을 먼저 확인하고, do-while은 본문을 먼저 실행해요.
void main() {
int likes = 0;
int checkCount = 0;
do {
checkCount++;
likes = likes + 18;
System.out.println("확인 " + checkCount + "회: 좋아요 " + likes + "개");
} while (likes < 50);
System.out.println("50개 돌파! 인기 게시물 등록!");
}
확인 1회: 좋아요 18개
확인 2회: 좋아요 36개
확인 3회: 좋아요 54개
50개 돌파! 인기 게시물 등록!
do-while은 do { ... } while (조건); 형태입니다.
끝에 **세미콜론(;)**이 붙는다는 걸 잊지 마세요.
둘의 차이를 눈으로 확인
조건이 처음부터 false면 어떻게 될까요?
void main() {
int count = 10;
// while: 조건이 false → 한 번도 실행 안 됨
while (count < 5) {
System.out.println("while 실행!");
count++;
}
// do-while: 조건이 false여도 한 번은 실행
count = 10;
do {
System.out.println("do-while 실행! count = " + count);
count++;
} while (count < 5);
}
do-while 실행! count = 10
while은 아예 실행되지 않지만, do-while은 한 번은 실행됩니다. "최소 한 번은 해봐야 하는 상황" — 예를 들어, 사용자에게 입력을 받아서 확인하는 경우 — 에 do-while이 어울려요.
🙋 학생 질문 — "for로 while을 대체할 수 있나요?"
네, 가능합니다. 모든 for 루프는 while로 바꿀 수 있고, 반대도 마찬가지예요. 하지만 읽기 쉬운 쪽을 고르는 게 중요합니다.
- 반복 횟수가 정해져 있다 → for가 더 읽기 쉬움
- 언제 끝날지 모른다 → while이 더 읽기 쉬움
어느 쪽이든 동작은 같지만, 코드를 읽는 사람이 의도를 빠르게 파악할 수 있는 쪽을 선택하면 됩니다.
Step 3: "반복을 멈추고, 건너뛰자" — break와 continue
반복문은 조건이 false가 될 때까지 계속 돕니다.
그런데 가끔은 도중에 멈추거나, 이번 바퀴만 건너뛰고 싶을 때가 있어요.
break — 반복을 즉시 탈출
게시물 20개를 하나씩 확인하다가, 좋아요가 50개 이상인 "인기 게시물"을 찾으면 바로 멈추고 싶다고 해봅시다.
// day04/BreakAndContinue.java
void main() {
for (int postId = 1; postId <= 20; postId++) {
int likes = postId * 7;
System.out.println("게시물 " + postId + ": 좋아요 " + likes + "개");
if (likes >= 50) {
System.out.println(">>> 인기 게시물 발견! 검색 중단");
break;
}
}
}
게시물 1: 좋아요 7개
게시물 2: 좋아요 14개
...
게시물 8: 좋아요 56개
>>> 인기 게시물 발견! 검색 중단
break를 만나는 순간 반복문 전체를 빠져나갑니다.
게시물 9~20은 확인하지 않아요.
continue — 이번 바퀴만 건너뛰기
비공개 계정은 건너뛰고, 공개 계정만 프로필을 표시하고 싶다면?
void main() {
for (int userId = 1; userId <= 10; userId++) {
boolean isPrivate = (userId % 3 == 0);
if (isPrivate) {
System.out.println("사용자 " + userId + ": 비공개 → 건너뜀");
continue;
}
System.out.println("사용자 " + userId + ": 공개 → 프로필 표시");
}
}
사용자 1: 공개 → 프로필 표시
사용자 2: 공개 → 프로필 표시
사용자 3: 비공개 → 건너뜀
사용자 4: 공개 → 프로필 표시
...
continue를 만나면 이번 바퀴의 나머지 코드를 건너뛰고 다음 바퀴로 넘어갑니다.
반복문 자체를 빠져나가지는 않아요.
break vs continue 비교
| 키워드 | 동작 | 비유 |
|---|---|---|
break |
반복 전체를 즉시 종료 | 달리기 중 "그만!" 하고 퇴장 |
continue |
이번 바퀴만 건너뛰고 다음 바퀴 시작 | 달리기 중 "이번은 패스!" 하고 다음 바퀴 |
while(true) + break 패턴
while(true)는 무한 반복입니다.
이 안에서 break 조건을 넣으면 "특정 조건에서만 멈추는 반복"을 만들 수 있어요.
void main() {
int currentFollowers = 0;
int day = 0;
while (true) {
day++;
currentFollowers = currentFollowers + 45;
if (currentFollowers >= 500) {
System.out.println(day + "일차에 500명 달성!");
break;
}
if (day % 3 == 0) {
System.out.println(day + "일차: " + currentFollowers + "명");
}
}
}
3일차: 135명 (진행 중...)
6일차: 270명 (진행 중...)
9일차: 405명 (진행 중...)
12일차에 500명 달성!
⚠️ while(true) 안에 break가 없으면 프로그램이 영원히 멈추지 않습니다.
반드시 탈출 조건을 넣어주세요!
Step 4: "배열을 한 바퀴 도는 법" — enhanced for
지금까지 반복문으로 숫자를 세고, 조건을 확인하고, 중간에 멈추는 것까지 배웠어요. 그런데 실제로 반복하고 싶은 건 숫자가 아니라 데이터인 경우가 많습니다.
"팔로워 5명의 이름을 출력하고 싶다."
이름을 담으려면 변수 5개가 필요할까요?
String name1 = "장원영";
String name2 = "카리나";
String name3 = "사쿠라";
String name4 = "김채원";
String name5 = "안유진";
이것도 복사 붙여넣기 문제와 똑같습니다. 여기서 잠깐, 오늘은 맛보기로만 살짝 소개하고, 다음 시간에 본격적으로 배울 개념이 있어요.
배열 — 여러 데이터를 한 줄에 담기
배열(Array) 은 같은 타입의 데이터를 한 줄로 묶는 방법입니다.
String[] followers = {"장원영", "카리나", "사쿠라", "김채원", "안유진"};
변수 5개 대신, 한 줄로 5개의 이름을 담았어요.
String[]에서 대괄호([])가 "여러 개"라는 뜻입니다.
기본 for로 배열 순회
배열의 각 칸에는 번호(인덱스) 가 붙어 있어요. 첫 번째 칸이 0번부터 시작합니다.
// day04/EnhancedForLoop.java
void main() {
String[] followers = {"장원영", "카리나", "사쿠라", "김채원", "안유진"};
for (int i = 0; i < followers.length; i++) {
System.out.println((i + 1) + "번째 팔로워: " + followers[i]);
}
}
1번째 팔로워: 장원영
2번째 팔로워: 카리나
3번째 팔로워: 사쿠라
4번째 팔로워: 김채원
5번째 팔로워: 안유진
followers.length는 배열의 길이(5)를 알려줍니다.
followers[i]로 i번째 칸의 데이터를 꺼내요.
enhanced for — 더 간결하게
인덱스가 필요 없고, 그냥 "전부 한 바퀴 돌고 싶다"면? Java에는 더 짧은 문법이 있습니다.
void main() {
String[] followers = {"장원영", "카리나", "사쿠라", "김채원", "안유진"};
for (String name : followers) {
System.out.println("팔로워: " + name);
}
}
팔로워: 장원영
팔로워: 카리나
...
팔로워: 안유진
for (타입 변수 : 배열) — 이 형태를 enhanced for(향상된 for문)라고 불러요.
"followers 배열에서 하나씩 꺼내서 name에 담아라"라는 뜻입니다.
기본 for vs enhanced for
| 항목 | 기본 for | enhanced for |
|---|---|---|
| 문법 | for (int i = 0; i < arr.length; i++) |
for (타입 변수 : arr) |
| 인덱스 | 사용 가능 (i) |
사용 불가 |
| 용도 | 인덱스가 필요할 때 | 전부 순회할 때 |
| 코드 길이 | 길다 | 짧다 |
인덱스 번호가 필요하면 기본 for, 그냥 순회만 하면 enhanced for. 상황에 맞는 걸 고르면 됩니다.
🙋 학생 질문 — "배열 인덱스가 왜 0부터 시작하나요?"
좋은 질문이에요! 컴퓨터 메모리에서 배열의 시작 위치를 기준으로 "몇 칸 떨어져 있는가"를 나타내기 때문입니다. 첫 번째 칸은 시작 위치에서 0칸 떨어져 있으니 0번이에요. 처음에는 헷갈리지만, 금방 익숙해집니다. 다음 시간에 배열을 본격적으로 다룰 때 더 자세히 살펴볼게요.
💡 배열은 다음 시간(Day 5)에서 선언, 초기화, 2차원 배열까지 본격적으로 배웁니다. 오늘은 "이런 게 있구나" 정도로 기억해 두세요!
Step 5: "반복 안에 반복" — 중첩 반복 기초
지금까지 배운 반복문은 한 줄짜리 데이터를 처리했어요. 1번부터 5번까지, 팔로워 목록 순회 등.
그런데 2차원 데이터 — 표, 격자, 시간표 같은 것 — 를 다루려면 어떻게 해야 할까요?
답은 반복 안에 반복을 넣는 것입니다.
알림 시간표 만들기
3일 동안, 매일 9시부터 12시까지 알림을 보내는 시간표를 출력해 봅시다.
// day04/NestedLoopsBasic.java
void main() {
for (int day = 1; day <= 3; day++) {
for (int hour = 9; hour <= 12; hour++) {
System.out.print("Day" + day + "-" + hour + "시 ");
}
System.out.println();
}
}
Day1-9시 Day1-10시 Day1-11시 Day1-12시
Day2-9시 Day2-10시 Day2-11시 Day2-12시
Day3-9시 Day3-10시 Day3-11시 Day3-12시
바깥 루프(day)가 한 번 돌 때마다, 안쪽 루프(hour)가 처음부터 끝까지 전부 돕니다.
바깥 = 행(row), 안쪽 = 열(column) 으로 생각하면 쉬워요.
게시물별 댓글 목록
게시물 3개에 각각 댓글 3개씩 달린 구조를 출력해 봅시다.
void main() {
for (int post = 1; post <= 3; post++) {
System.out.println("게시물 " + post + ":");
for (int comment = 1; comment <= 3; comment++) {
System.out.println(" ㄴ 댓글 " + comment);
}
}
}
게시물 1:
ㄴ 댓글 1
ㄴ 댓글 2
ㄴ 댓글 3
게시물 2:
ㄴ 댓글 1
ㄴ 댓글 2
ㄴ 댓글 3
게시물 3:
ㄴ 댓글 1
ㄴ 댓글 2
ㄴ 댓글 3
바깥 루프가 "게시물"을 돌고, 안쪽 루프가 각 게시물의 "댓글"을 돕니다. 이런 구조를 중첩 반복(Nested Loop) 이라고 불러요.
실행 순서 정리
중첩 반복에서 가장 중요한 건 누가 먼저 도는가입니다.
| 단계 | 바깥 루프 (post) | 안쪽 루프 (comment) |
|---|---|---|
| 1 | post = 1 | comment = 1, 2, 3 |
| 2 | post = 2 | comment = 1, 2, 3 |
| 3 | post = 3 | comment = 1, 2, 3 |
바깥이 한 칸 움직이면, 안쪽이 전부 돕니다. 시계 바늘과 비슷해요. 분침(안쪽)이 한 바퀴 돌아야 시침(바깥)이 한 칸 움직이죠.
🙋 학생 질문 — "3중 반복도 가능한가요?"
가능합니다. 하지만 깊어질수록 코드를 읽기가 점점 어려워져요. 실무에서도 3중 이상은 웬만하면 피하고, 메서드를 분리하는 방식으로 해결합니다. 지금은 2중 반복까지 확실히 이해하면 충분해요!
Step 6: "데이터를 눈으로 보자" — 해시태그 막대 그래프
중첩 반복을 배웠으니, 이걸로 뭔가 눈에 보이는 결과물을 만들어 봅시다.
인스타그램에서 어떤 해시태그가 인기 있는지 막대 그래프로 시각화하면 어떨까요?
█ 문자를 반복해서 막대를 그릴 수 있습니다.
기본 막대 그래프
// day04/HashtagBarChart.java
void main() {
String[] hashtags = {"#맛집 ", "#여행 ", "#일상 ", "#운동 ", "#카페 "};
int[] counts = {12, 8, 15, 6, 10};
for (int i = 0; i < hashtags.length; i++) {
System.out.print(hashtags[i] + " ");
for (int j = 0; j < counts[i]; j++) {
System.out.print("█");
}
System.out.println(" (" + counts[i] + ")");
}
}
#맛집 ████████████ (12)
#여행 ████████ (8)
#일상 ███████████████ (15)
#운동 ██████ (6)
#카페 ██████████ (10)
바깥 루프는 각 해시태그를 돌고, 안쪽 루프는 █ 문자를 counts[i]번 반복합니다.
숫자만 나열하는 것보다 막대로 보니 한눈에 비교되죠?
어떻게 동작할까요?
#일상의 경우를 따라가 봅시다.
counts[2]는 15입니다.
- 바깥 루프:
i = 2→"#일상 "출력 - 안쪽 루프:
j = 0부터j < 15까지 →█를 15번 출력 - 줄바꿈 +
(15)출력
이게 중첩 반복의 핵심입니다. 바깥이 "무엇을", 안쪽이 "얼마나" 를 담당해요.
시간대별 활동량 차트
다른 모양의 기호로도 그래프를 만들 수 있어요.
void main() {
String[] hours = {"06-09시", "09-12시", "12-15시",
"15-18시", "18-21시", "21-24시"};
int[] activity = {3, 7, 5, 8, 14, 11};
for (int i = 0; i < hours.length; i++) {
System.out.print(hours[i] + " | ");
for (int j = 0; j < activity[i]; j++) {
System.out.print("●");
}
System.out.println(" " + activity[i] + "건");
}
}
06-09시 | ●●● 3건
09-12시 | ●●●●●●● 7건
...
18-21시 | ●●●●●●●●●●●●●● 14건
21-24시 | ●●●●●●●●●●● 11건
저녁 6시~9시가 가장 활발하네요. 실제 인스타그램 인사이트에서도 비슷한 패턴이 나옵니다!
Step 7: "인스타 피드를 그려보자" — 3x3 그리드 UI
인스타그램 프로필에 들어가면 게시물이 3열 격자로 배치되어 있죠? 이 레이아웃을 중첩 반복 + 조건문 조합으로 콘솔에서 그려봅시다.
3x3 피드 그리드
// day04/InstagramFeedGrid.java
void main() {
int rows = 3;
int cols = 3;
int postNumber = 0;
for (int row = 0; row < rows; row++) {
// 상단 테두리
for (int col = 0; col < cols; col++) {
System.out.print("+--------");
}
System.out.println("+");
// 게시물 번호
for (int col = 0; col < cols; col++) {
postNumber++;
if (postNumber < 10) {
System.out.print("| [0" + postNumber + "] ");
} else {
System.out.print("| [" + postNumber + "] ");
}
}
System.out.println("|");
}
// 하단 테두리
for (int col = 0; col < cols; col++) {
System.out.print("+--------");
}
System.out.println("+");
}
+--------+--------+--------+
| [01] | [02] | [03] |
+--------+--------+--------+
| [04] | [05] | [06] |
+--------+--------+--------+
| [07] | [08] | [09] |
+--------+--------+--------+
꽤 그럴듯한 격자가 만들어졌어요!
코드 분석
이 코드에는 중첩 반복이 세 군데 들어 있습니다.
- 테두리 루프:
+--------를 3번 반복 - 게시물 번호 루프:
| [01]를 3번 반복 - 하단 테두리: 마지막 줄 처리
바깥 루프(row)가 한 번 돌 때마다, 안쪽에서 테두리와 게시물 번호를 각각 그립니다.
if (postNumber < 10) 조건으로 한 자리/두 자리 숫자의 정렬을 맞추고 있어요.
좋아요 히트맵
같은 3x3 격자에 데이터를 입혀 봅시다. 좋아요 수에 따라 다른 표시를 넣으면 히트맵이 됩니다.
void main() {
int[] likes = {42, 128, 7, 95, 210, 33, 67, 150, 12};
int index = 0;
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
String heat;
if (likes[index] >= 100) {
heat = " HOT ";
} else if (likes[index] >= 50) {
heat = " warm";
} else {
heat = " - ";
}
System.out.print("[" + heat + "]");
index++;
}
System.out.println();
}
System.out.println();
System.out.println("HOT = 100+ 좋아요, warm = 50+, - = 50 미만");
}
[ - ][ HOT ][ - ]
[ warm][ HOT ][ - ]
[ warm][ HOT ][ - ]
HOT = 100+ 좋아요, warm = 50+, - = 50 미만
중첩 반복(격자 순회) + 조건문(좋아요 등급 분류) + 배열(데이터 저장). Day 2~4에서 배운 것들이 한 번에 조합되는 순간입니다!
Step 8: "나의 첫 반복 프로젝트" — 인스타 팔로워 분석기
마지막 Step에서는 오늘 배운 모든 기술을 조합해서 인스타그램 프로필 분석기를 만들어 봅시다. Day 3의 프로필 카드를 업그레이드하는 거예요!
완성 코드
// day04/InstagramFollowerListDemo.java
void main() {
String username = "java_learner_2026";
int postCount = 42;
int followerCount = 1500;
int followingCount = 280;
boolean isVerified = true;
// 프로필 카드 출력
System.out.println("========================================");
System.out.println(" 인스타그램 프로필 카드 v3");
System.out.println("========================================");
System.out.println();
System.out.println("@" + username + (isVerified ? " ✓" : ""));
System.out.println("게시물 " + postCount
+ " | 팔로워 " + followerCount
+ " | 팔로잉 " + followingCount);
}
여기까지는 Day 2~3에서 이미 할 수 있었던 부분이에요. 이제 반복문의 힘을 더합니다.
팔로워 목록 — enhanced for
String[] followers = {"장원영", "카리나", "사쿠라", "김채원", "안유진"};
System.out.println("--- 팔로워 목록 ---");
int number = 0;
for (String name : followers) {
number++;
System.out.println(number + ". " + name);
}
System.out.println("총 " + followers.length + "명");
--- 팔로워 목록 ---
1. 장원영
2. 카리나
3. 사쿠라
4. 김채원
5. 안유진
총 5명
게시물 좋아요 막대 그래프 — 중첩 반복
int[] postLikes = {42, 128, 7, 95, 210};
System.out.println("--- 최근 게시물 좋아요 ---");
int total = 0;
int max = 0;
int bestPost = 0;
for (int i = 0; i < postLikes.length; i++) {
total = total + postLikes[i];
if (postLikes[i] > max) {
max = postLikes[i];
bestPost = i + 1;
}
System.out.print("게시물 " + (i + 1) + ": ");
int barLen = postLikes[i] / 10;
for (int j = 0; j < barLen; j++) {
System.out.print("█");
}
System.out.println(" " + postLikes[i] + "개");
}
System.out.println();
System.out.println("총 좋아요: " + total + "개");
System.out.println("평균: " + (total / postLikes.length) + "개");
System.out.println("최고 인기: 게시물 " + bestPost
+ " (" + max + "개)");
게시물 1: ████ 42개
게시물 2: ████████████ 128개
게시물 3: 7개
게시물 4: █████████ 95개
게시물 5: █████████████████████ 210개
총 좋아요: 482개
평균: 96개
최고 인기: 게시물 5 (210개)
인기 게시물 필터 — continue
System.out.println("--- 좋아요 50개 이상만 ---");
int found = 0;
for (int i = 0; i < postLikes.length; i++) {
if (postLikes[i] < 50) {
continue;
}
found++;
System.out.println("게시물 " + (i + 1) + ": "
+ postLikes[i] + "개");
}
System.out.println("인기 게시물 " + found + "개 발견!");
게시물 2: 128개
게시물 4: 95개
게시물 5: 210개
인기 게시물 3개 발견!
하나의 프로그램 안에서 for, enhanced for, 중첩 반복, continue가 모두 등장했어요.
Day 3의 조건문(if/else)까지 합치면, 이제 꽤 쓸 만한 프로그램을 만들 수 있습니다!
마무리
오늘 배운 내용을 정리해 볼게요.
- for — 정해진 횟수만큼 반복 (초기값; 조건; 증감)
- while — 조건이 참인 동안 반복 (횟수를 모를 때)
- do-while — 최소 한 번은 실행하고 조건 확인
- break — 반복을 즉시 탈출
- continue — 이번 바퀴만 건너뛰기
- enhanced for — 배열을 간결하게 순회
- 중첩 반복 — 2차원 데이터(표, 그래프, 그리드)를 처리
Day 2에서 데이터를 기억하는 법을 배웠고, Day 3에서 판단하는 법을 배웠고, 오늘은 반복하는 법을 배웠습니다. 기억 + 판단 + 반복. 이 세 가지가 모든 프로그램의 기본 구조예요.
그런데 오늘 Step 4에서 배열을 살짝 맛봤는데, 아직 부족한 게 많아요.
팔로워 50명의 이름을 담으려면 String[] followers = {... 50개 ...}?
배열을 중간에 늘리거나 줄일 수 있을까요?
인덱스 범위를 벗어나면 어떻게 될까요?
다음 시간에는 배열을 본격적으로 파헤칩니다.
1차원 배열, 2차원 배열, 그리고 배열을 편하게 다루는 도구(Arrays 유틸리티)까지!
과제
[실습] 숫자 피라미드
중첩 반복을 사용해서 다음과 같은 숫자 피라미드를 출력하는 프로그램을 만들어 보세요.
출력 예시 (N = 5):
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
요구사항:
N은 변수로 선언 (값을 바꾸면 피라미드 크기가 달라져야 함)- 바깥 루프는 행(1~N), 안쪽 루프는 열(1~현재 행)
System.out.print()과System.out.println()을 적절히 조합
[실습] 인스타그램 팔로워 증감 시뮬레이터
while 루프와 break/continue를 활용해서 팔로워 수 증감을 시뮬레이션하는 프로그램을 만들어 보세요.
동작 규칙:
- 시작 팔로워: 100명
- 명령 배열:
String[] commands = {"follow", "follow", "unfollow", "spam", "follow", "unfollow", "follow", "follow", "quit"}; "follow"→ 팔로워 +1"unfollow"→ 팔로워 -1 (단, 0 미만이면 "더 이상 줄일 수 없습니다" 출력 후 건너뜀)"spam"→ "스팸 명령 무시" 출력 후 건너뜀 (continue활용)"quit"→ "시뮬레이션 종료!" 출력 후 멈춤 (break활용)- 각 명령 처리 후 현재 팔로워 수 출력
생각해볼 주제
1. "for와 while, 언제 뭘 써야 할까?"
for 루프와 while 루프는 할 수 있는 일이 같습니다. 어떤 반복이든 for로도, while로도 쓸 수 있어요. 그렇다면 왜 두 가지가 따로 있을까요? 각각 어떤 상황에서 더 자연스러운지, 본인만의 기준을 세워 보세요.
2. "무한 루프는 항상 나쁜 걸까?"
while(true)는 프로그램을 영원히 멈추지 않게 합니다.
실수로 만들면 위험하죠.
하지만 실제 프로그램(게임, 서버, 채팅 앱)에서 무한 루프는 의도적으로 사용됩니다.
어떤 상황에서 무한 루프가 유용한지, 그리고 안전하게 멈추는 방법은 무엇인지 생각해 보세요.
3. "반복문 없이 프로그래밍이 가능할까?"
만약 for, while, do-while이 모두 사라진다면? 같은 코드를 100번 복사하는 것 말고, 다른 방법이 있을까요? (힌트: Day 6에서 배울 메서드와 재귀에 답이 있습니다.)
✅ 예시 답안정답 보기
🎯 [과제 1 예시 답안] 숫자 피라미드
중첩 반복을 사용해서 숫자 피라미드를 출력하는 프로그램입니다.
채점 포인트
| 항목 | 배점 | 기준 |
|---|---|---|
| 중첩 반복 구조 | 30% | 바깥 루프(행) + 안쪽 루프(열) 사용 |
| 안쪽 루프 종료 조건 | 30% | col <= row로 현재 행까지만 출력 |
| N을 변수로 선언 | 20% | 값을 바꾸면 피라미드 크기가 달라짐 |
| 출력 형식 | 20% | 숫자 사이 공백, 줄바꿈 정확 |
예시 코드
void main() {
int n = 5;
for (int row = 1; row <= n; row++) {
for (int col = 1; col <= row; col++) {
System.out.print(col + " ");
}
System.out.println();
}
}
실행 결과:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
핵심 포인트
바깥 루프의 변수 row가 안쪽 루프의 종료 조건에 들어가는 것이 핵심입니다.
row = 1일 때 안쪽 루프는 1번, row = 3일 때는 3번 돕니다.
이렇게 "바깥 루프 변수가 안쪽 루프의 범위를 결정하는 패턴"은 2차원 데이터를 다룰 때 자주 등장합니다.
n 값을 10으로 바꿔보면 더 큰 피라미드가 만들어지는 것을 확인할 수 있어요.
두 자리 숫자가 나오면 정렬이 흐트러지는데, 이건 나중에 String.format()이나 printf()를 배우면 해결됩니다.
🎯 [과제 2 예시 답안] 인스타그램 팔로워 증감 시뮬레이터
while 루프와 break/continue를 조합해서 팔로워 수 증감을 시뮬레이션합니다.
채점 포인트
| 항목 | 배점 | 기준 |
|---|---|---|
| enhanced for로 명령 배열 순회 | 20% | for (String cmd : commands) 사용 |
break 사용 |
20% | "quit"에서 반복 종료 |
continue 사용 |
20% | "spam"에서 건너뛰기 |
| 경계 조건 처리 | 20% | 팔로워 0 미만 방지 |
| 매 명령 후 현재 상태 출력 | 20% | 팔로워 수 변화 추적 가능 |
예시 코드
void main() {
int followers = 100;
String[] commands = {"follow", "follow", "unfollow",
"spam", "follow", "unfollow",
"follow", "follow", "quit"};
System.out.println("시작 팔로워: " + followers + "명");
System.out.println();
for (String cmd : commands) {
// quit → 즉시 종료
if (cmd.equals("quit")) {
System.out.println("[quit] 시뮬레이션 종료!");
break;
}
// spam → 무시하고 다음으로
if (cmd.equals("spam")) {
System.out.println("[spam] 스팸 명령 무시");
continue;
}
// follow / unfollow 처리
if (cmd.equals("follow")) {
followers++;
System.out.println("[follow] +1 → 현재 " + followers + "명");
} else if (cmd.equals("unfollow")) {
if (followers <= 0) {
System.out.println("[unfollow] 더 이상 줄일 수 없습니다");
continue;
}
followers--;
System.out.println("[unfollow] -1 → 현재 " + followers + "명");
}
}
System.out.println();
System.out.println("최종 팔로워: " + followers + "명");
}
실행 결과:
시작 팔로워: 100명
[follow] +1 → 현재 101명
[follow] +1 → 현재 102명
[unfollow] -1 → 현재 101명
[spam] 스팸 명령 무시
[follow] +1 → 현재 102명
[unfollow] -1 → 현재 101명
[follow] +1 → 현재 102명
[follow] +1 → 현재 103명
[quit] 시뮬레이션 종료!
최종 팔로워: 103명
핵심 포인트
이 과제에서 break와 continue의 차이가 명확하게 드러납니다.
break는"quit"을 만나면 반복 전체를 종료합니다. 남은 명령은 실행하지 않아요.continue는"spam"을 만나면 이번 바퀴의 나머지를 건너뛰고 다음 명령으로 넘어갑니다.
followers <= 0 체크도 중요합니다.
실제 프로그램에서 값이 음수가 되면 안 되는 경우, 이렇게 경계 조건을 검사하는 습관이 필요해요.
💡 [생각해볼 주제 1 예시 답안] "for와 while, 언제 뭘 써야 할까?"
문제 상황 요약
for와 while은 할 수 있는 일이 동일합니다. 둘 다 조건이 참인 동안 반복하고, 둘 다 같은 결과를 만들 수 있어요. 그렇다면 왜 굳이 두 가지를 구분해서 쓸까요?
튜터의 가이드 및 해설
핵심은 "읽는 사람이 의도를 빠르게 파악할 수 있는가" 입니다.
for를 쓰면 좋은 상황:
- "1부터 10까지", "배열의 처음부터 끝까지"처럼 반복 횟수가 명확할 때
- for 문의 괄호 안에 시작, 조건, 변화가 한눈에 보이니까 "아, N번 도는구나" 하고 바로 이해됩니다
while을 쓰면 좋은 상황:
- "팔로워가 1만 명이 될 때까지", "사용자가 종료를 선택할 때까지"처럼 언제 끝날지 모를 때
- 조건만 보면 되니까 "아, 이 조건이 만족되면 끝나는구나" 하고 의도가 드러납니다
do-while을 쓰면 좋은 상황:
- "일단 한 번은 해봐야 하는" 경우. 메뉴 출력, 입력 받기, 게임 라운드 등
- 실무에서 가장 드물게 쓰이지만, 딱 맞는 상황에서는 가장 자연스럽습니다
코드는 사람이 읽는 것입니다. 컴퓨터에게는 for든 while이든 상관없지만, 읽는 사람에게는 의도가 명확한 쪽이 좋은 코드예요.
🎯 면접관을 홀리는 핵심 멘트
"반복 횟수가 정해져 있으면 for, 종료 조건만 있고 횟수가 불확실하면 while을 씁니다. 기능적으로는 동일하지만, 코드를 읽는 사람이 반복의 의도를 즉시 파악할 수 있는 쪽을 선택하는 게 중요합니다."
💡 [생각해볼 주제 2 예시 답안] "무한 루프는 항상 나쁜 걸까?"
문제 상황 요약
while(true)는 프로그램을 멈추지 않게 만드는 위험한 코드처럼 보입니다.
하지만 실제 프로그램에서는 의도적으로 무한 루프를 사용하는 경우가 많습니다.
튜터의 가이드 및 해설
무한 루프가 나쁜 경우는 딱 하나입니다. 탈출 조건 없이 실수로 만들었을 때 입니다.
반대로 의도적인 무한 루프는 실무에서 매우 흔해요.
게임 루프: 게임은 플레이어가 종료 버튼을 누를 때까지 매 프레임 화면을 그리고, 입력을 받고, 상태를 갱신합니다.
이 "게임 루프"가 while(true) 기반이에요.
서버: 웹 서버는 클라이언트의 요청을 기다리며 무한히 대기합니다. "요청이 오면 처리하고, 다시 기다리고, 또 요청이 오면 처리하고..." — 이게 무한 루프입니다.
채팅 앱: 메시지를 계속 받아서 화면에 표시하는 것도 무한 루프예요.
이 모든 경우에 공통점이 있습니다. "루프 안에 반드시 탈출 조건이 있다" 는 것이에요. 게임은 종료 버튼, 서버는 shutdown 명령, 채팅은 로그아웃.
무한 루프 자체가 나쁜 게 아니라, 탈출 조건 없는 무한 루프가 나쁜 것입니다.
🎯 면접관을 홀리는 핵심 멘트
"무한 루프는 게임 루프, 서버 이벤트 루프, 메시지 리스너 등 실무에서 의도적으로 사용됩니다. 핵심은 반드시 명확한 탈출 조건(break, shutdown hook, 종료 플래그)을 함께 설계하는 것입니다."
💡 [생각해볼 주제 3 예시 답안] "반복문 없이 프로그래밍이 가능할까?"
문제 상황 요약
만약 for, while, do-while이 모두 없다면, 같은 작업을 반복하는 방법이 있을까요?
튜터의 가이드 및 해설
답은 "가능하다" 입니다. 반복문을 대체하는 방법이 두 가지 있어요.
1. 재귀(Recursion)
메서드가 자기 자신을 호출하는 방식입니다. Day 6에서 메서드를 배운 뒤, 재귀의 기본 개념을 만나게 돼요.
// 1부터 5까지 출력 — 재귀 버전 (Day 6 예고)
void countUp(int current, int max) {
if (current > max) return;
System.out.println(current);
countUp(current + 1, max);
}
반복문 없이도 1부터 5까지 출력할 수 있습니다! 하지만 재귀는 너무 깊어지면 메모리 문제가 생길 수 있어서, 단순 반복에는 for/while이 더 적합해요.
2. 스트림(Stream)
Day 25에서 배울 Stream API를 쓰면 반복문 없이 데이터를 처리할 수 있습니다. "어떻게 반복할지"가 아니라 "무엇을 할지"만 선언하는 방식이에요.
지금은 "반복문 말고도 다른 길이 있다"는 것만 기억해 두세요. 반복문은 가장 기본적이고 직관적인 방법이고, 나머지는 특수한 상황에서 쓰는 도구입니다.
프로그래밍에는 같은 목표에 도달하는 여러 길이 있고, 상황에 맞는 도구를 고르는 것이 실력입니다.
🎯 면접관을 홀리는 핵심 멘트
"반복문 없이도 재귀나 Stream으로 같은 결과를 낼 수 있습니다. 반복문은 명령형(어떻게 반복할지), Stream은 선언형(무엇을 할지) 접근입니다. 단순 반복에는 for/while이 직관적이고, 데이터 변환 파이프라인에는 Stream이 더 적합합니다."