지금까지는 코드가 위에서 아래로 한 줄씩 실행됐어요. 이번 장에서는 상황(조건)에 따라 다른 길로 가는 방법을 배웁니다. if와 switch, 두 갈래 도구를 천천히 익혀봐요.
{ }의 중요성과 == vs = 실수를 피할 수 있어요.break와 fall-through 함정을 알아요.지금까지 배운 코드는 맨 위에서 맨 아래로 한 줄씩 순서대로 실행됐어요. 하지만 진짜 프로그램은 그렇게 단순하지 않죠. "나이가 19살 이상이면 입장 허용, 아니면 거부" 처럼 상황에 따라 다르게 동작해야 해요. 이렇게 조건에 따라 실행할 코드를 골라 주는 문법을 조건문(conditional statement)이라고 해요.
if·switch·삼항이 모두 이 "분기"를 만드는 도구예요. 나무가 가지(branch)로 갈라지듯 흐름이 나뉜다고 생각하면 쉬워요.true) 또는 거짓(false), 즉 boolean 타입이어야 해요.age >= 19, score == 100, isMember — 모두 결과가 true/false죠.
💡 C 언어에서는 숫자 0을 거짓, 그 외를 참으로 취급했지만, 자바는 그걸 허용하지 않아요. if (1) 처럼 숫자를 넣으면 컴파일 에러가 납니다. 반드시 boolean만!
if는 "만약 ~라면"이에요. 조건이 참일 때만 중괄호 { } 안의 코드를 실행해요. 참이 아니면 그 블록을 건너뛰죠. 가장 단순한 형태부터 볼게요.
int age = 20;
if (age >= 19) { // 조건식 결과가 true이면
System.out.println("입장 가능합니다.");
}
System.out.println("다음 코드로 진행");
{ }로 묶은 코드 한 덩어리를 말해요. if가 참일 때 실행되는 게 바로 이 블록이고, 여러 줄을 하나로 묶어 "이만큼을 함께 실행해라"라고 표시하는 거예요. 조건문·반복문에서 계속 나오는 기본 단위랍니다.이번엔 참일 때와 아닐 때를 갈라야 하면? 뒤에 else(그렇지 않으면)를 붙여요. 둘 중 정확히 하나만 실행돼요.
int age = 15;
if (age >= 19) {
System.out.println("성인입니다.");
} else {
System.out.println("미성년자입니다."); // age가 19 미만이므로 이쪽 실행
}
경우가 셋 이상이면 중간에 else if를 여러 번 넣어요. 핵심 원리는 딱 하나예요 — 위에서부터 차례로 검사하다가, 처음으로 참이 되는 블록 하나만 실행하고 나머지는 전부 건너뛴다.
int score = 82;
char grade;
if (score >= 90) { // 82 >= 90 → false, 건너뜀
grade = 'A';
} else if (score >= 80) { // 82 >= 80 → true! 여기 실행하고 끝
grade = 'B';
} else if (score >= 70) { // (검사조차 안 함)
grade = 'C';
} else { // (검사조차 안 함)
grade = 'F';
}
System.out.println("학점: " + grade); // 출력: 학점: B
score = 82는 >= 80도 참이고 >= 70도 참이에요. 그런데도 결과는 B 하나뿐이죠.else if는 "앞의 조건들이 전부 거짓일 때만" 검사돼요. 위에서 >= 80이 참으로 걸리는 순간, 그 아래는 아예 쳐다보지도 않고 if 전체를 빠져나갑니다.
💡 그래서 조건의 순서가 중요해요. 만약 >= 70을 맨 위에 두면, 82점도 90점도 전부 거기서 걸려 잘못된 학점이 나와요. 범위 조건은 보통 좁은(까다로운) 것부터 위에 둡니다.
{ }를 생략할 수도 있지만, 나중에 줄을 추가하다 버그가 생기기 쉬워요. 초보일수록 무조건 { }로 감싸는 습관이 안전합니다.조건문 안에 또 조건문을 넣을 수 있어요. 이걸 중첩 if(nested if)라고 해요. "회원인 경우에 한해서, 다시 등급을 따진다" 처럼 조건을 단계적으로 좁혀 갈 때 써요.
boolean isMember = true;
int point = 1200;
if (isMember) { // ① 먼저 회원인지 확인
if (point >= 1000) { // ② 회원인 경우에만 포인트 확인
System.out.println("VIP 회원입니다.");
} else {
System.out.println("일반 회원입니다.");
}
} else {
System.out.println("회원이 아닙니다.");
}
// 출력: VIP 회원입니다.
{ }를 생략하면, else는 "가장 가까운 짝 없는 if"에 달라붙어요. 아래처럼 보기와 다르게 동작하는 유명한 함정이 있어요.
int x = 10;
if (x > 0)
if (x > 100)
System.out.println("아주 큼");
else // 들여쓰기는 바깥 if처럼 보이지만…
System.out.println("음수?"); // 실제로는 안쪽 if의 else!
위 else는 들여쓰기와 무관하게 바로 위 안쪽 if (x > 100)의 짝이에요. x가 10이라 x > 100이 거짓 → "음수?"가 출력돼요(직관과 반대!).
💡 이래서 중괄호를 꼭 써야 해요. { }로 감싸면 어떤 if에 붙는 else인지 눈으로 명확히 보여서 이런 사고를 막을 수 있어요.
== (비교) vs = (대입)
값이 같은지 비교할 때는 등호 두 개 ==, 값을 넣을(대입) 때는 등호 한 개 = 예요. 조건식에서 실수로 =를 쓰면 안 돼요.
int n = 5;
if (n = 3) { ... } // ❌ 컴파일 에러! n에 3을 "대입"하려는 것
if (n == 3) { ... } // ✅ n이 3과 "같은가"를 비교 (여기선 false)
💡 다행히 자바는 if 조건이 boolean이어야 하므로, int에 대입하는 n = 3은 컴파일 에러로 바로 걸러 줘요. (C에서는 그냥 통과돼 버그가 되던 부분이에요.) 단, boolean flag = true; 상태에서 if (flag = false)는 에러 없이 통과하니 여전히 조심!
&&(그리고)·||(또는) 같은 논리 연산자(CH 05)로 합치거나, 뒤에 배울 switch로 바꾸면 훨씬 깔끔해질 때가 많아요.switch는 하나의 값을 여러 후보(case)와 차례로 맞춰 보고, 일치하는 곳으로 점프하는 문법이에요. else if가 길게 늘어질 때, 값 비교라면 switch가 더 읽기 좋아요.
int day = 3;
switch (day) { // day 값을 아래 case들과 비교
case 1:
System.out.println("월요일");
break; // ★ 이 case 끝! switch를 빠져나감
case 2:
System.out.println("화요일");
break;
case 3:
System.out.println("수요일"); // day가 3 → 여기로 점프
break;
default: // 어떤 case에도 안 맞으면
System.out.println("알 수 없는 요일");
}
// 출력: 수요일
구조는 switch(값){ case A: … break; case B: … break; default: … } 예요. default는 어떤 case에도 맞지 않을 때 실행되는 곳으로, if의 else와 비슷해요(생략 가능).
break를 빠뜨리면 fall-through!
switch는 일치하는 case로 점프한 뒤, break를 만날 때까지 아래 case들을 멈추지 않고 계속 실행해요. 이걸 fall-through(아래로 흘러감)라고 해요. break를 깜빡하면 이렇게 됩니다.
int day = 1;
switch (day) {
case 1:
System.out.println("월요일"); // day가 1 → 여기 실행
// break; ← 깜빡 누락!
case 2:
System.out.println("화요일"); // break 없어서 아래로 "흘러" 여기도 실행!
break;
case 3:
System.out.println("수요일");
break;
}
// 출력:
// 월요일
// 화요일 ← case 2까지 흘러내려 함께 출력됨!
💡 대부분의 실수 원인이 바로 이 break 누락이에요. 전통형 switch에서는 각 case 끝에 break;를 반드시 챙기세요.
int day = 6;
switch (day) {
case 6:
case 7: // case 6에 break가 없어 여기로 흘러옴
System.out.println("주말!");
break;
default:
System.out.println("평일");
}
// 출력: 주말!
💡 이렇게 case를 연달아 쌓아 "6이거나 7이면 주말"처럼 묶을 수 있어요. 하지만 실수인지 의도인지 헷갈리기 쉬워서, 뒤에 나올 화살표 switch가 이런 상황을 더 안전하게 만들어 줘요.
int·char 같은 정수 계열과 enum에 쓸 수 있었고, Java 7부터는 String(문자열)도 switch에 쓸 수 있어요. 단, boolean·long·실수(double) 등은 (전통형에서는) 쓸 수 없어요.MON, TUE, WED처럼 미리 정해 둔 값들의 목록을 이름으로 만들어 쓰는 특별한 타입이에요. "요일", "등급"처럼 정해진 몇 가지 중 하나를 나타낼 때 딱이라 switch와 잘 어울려요. 지금은 "이런 것도 있구나" 정도만 알아두면 되고, 만드는 법은 뒤 챕터에서 배워요.->를 쓰면 fall-through가 사라져서 훨씬 안전하고 짧아요.Java 14부터 정식으로 들어온 화살표 switch는 case 값 -> 실행; 형태예요. 콜론 : 대신 화살표 ->를 쓰고, break가 필요 없어요. 해당 case만 실행하고 자동으로 빠져나가거든요.
int day = 3;
switch (day) {
case 1 -> System.out.println("월요일");
case 2 -> System.out.println("화요일");
case 3 -> System.out.println("수요일"); // 여기만 실행되고 끝 (fall-through 없음!)
default -> System.out.println("알 수 없는 요일");
}
// 출력: 수요일
여러 값을 한 case에 묶고 싶으면, 라벨을 쉼표로 나열하면 돼요. 전통형에서 case를 쌓던 걸 한 줄로 깔끔하게 표현해요.
int day = 6;
switch (day) {
case 6, 7 -> System.out.println("주말!"); // 여러 label을 쉼표로
default -> System.out.println("평일");
}
// 출력: 주말!
화살표 switch는 값을 돌려주는(반환) 형태로도 쓸 수 있어요. 한 줄이면 그대로, 여러 줄이라 { } 블록이 필요하면 yield로 결과를 내보내요.
int day = 3;
// switch가 결과 값을 돌려줘서 변수에 담을 수 있어요 (switch 표현식)
String name = switch (day) {
case 1 -> "월요일";
case 2 -> "화요일";
case 3 -> "수요일";
default -> {
String s = "요일 " + day;
yield s; // 블록에서 값을 돌려줄 땐 yield
}
};
System.out.println(name); // 출력: 수요일
:) vs 화살표(->) 한눈에
전통형 — case A: 뒤에 여러 문장을 쓰고, 각 case마다 break를 직접 챙겨야 해요. 안 쓰면 fall-through로 아래까지 실행돼요.case A -> 로 쓰고, break가 필요 없어요. fall-through가 아예 없어서 실수할 여지가 적어요. 여러 값은 case A, B ->로 묶고, 값 반환엔 yield를 써요.
💡 새 코드라면 화살표 switch가 더 안전하고 짧아서 권장돼요. 다만 예전 코드나 교재에는 전통형이 많으니 둘 다 읽을 줄 알아야 해요. (화살표 문법은 Java 14 이상에서 동작)
먼저 삼항 연산자(CH 05)를 다시 떠올려요. 조건 ? 참일때값 : 거짓일때값 형태로, 둘 중 하나의 값을 골라 담는 아주 짧은 분기예요.
int score = 82;
// if 버전
String result;
if (score >= 60) {
result = "합격";
} else {
result = "불합격";
}
// 삼항 버전 — 위와 완전히 동일, 한 줄로!
String result2 = (score >= 60) ? "합격" : "불합격";
| 도구 | 잘 맞는 상황 | 특징 / 주의 |
|---|---|---|
| if / else if | 범위 조건(>=, <), 여러 변수를 조합한 복잡한 조건 |
가장 자유롭고 만능. 경우가 많고 값 비교면 장황해질 수 있음 |
| switch | 하나의 값을 딱 떨어지는 여러 경우로 나눌 때 (요일·메뉴번호·등급코드 등) | 가독성 좋음. 범위 비교엔 부적합. 전통형은 break 주의 |
삼항 ? : |
둘 중 하나의 값을 골라 변수에 담거나 바로 쓸 때 | 아주 짧음. 여러 문장 실행엔 부적합. 겹쳐 쓰면 오히려 읽기 어려움 |
if 계열.switch.if로 다 짜도 괜찮아요. 익숙해지면 "이 경우엔 switch가 깔끔하네", "이건 삼항 한 줄이면 되네" 하는 감이 생깁니다.
{ }는 항상 쓰는 게 안전해요. else는 가장 가까운 짝 없는 if에 붙어요. 비교는 ==, 대입은 =(혼동 주의).break를 빠뜨리면 아래 case까지 흘러가는 fall-through 함정이 있어요. 각 case에 break를 챙기세요.case 값 -> 형태로 break가 필요 없고, 여러 label은 쉼표로 묶고, 값 반환엔 yield를 써요.