조건문 — 코드의 길을 나눈다
Article
점수가 90점인지 확인하려다 == 를 하나 빠뜨렸다.
int score = 80;
if (score = 90) {
System.out.println("만점에 가깝다");
}
- error: incompatible types: int cannot be converted to boolean
- if (score = 90) {
- ^
컴파일러가 막았다.
score = 90 은 3강에서 봤듯 넣는다는 뜻이다. 넣고 나면 그 결과인 90 이 남는다. if 는 90 을 받아든 셈이다.
어떤 언어들은 여기서 90 을 "0이 아니니까 참"으로 취급하고 조용히 넘어간다. 그리고 조건문은 언제나 참이 되며, score 는 영문도 모른 채 90 으로 바뀐다. 찾기 힘든 버그다.
자바의 if 는 boolean 만 받는다. 이번 강의는 그 까다로움에서 시작한다.
if 는 boolean 만 받는다
0 도 안 되고 null 도 안 된다. 오직 true 또는 false 다.
int score = 85;
if (score >= 90) {
System.out.println("A");
} else if (score >= 80) {
System.out.println("B");
} else {
System.out.println("C");
}
- B
else if 는 위에서부터 차례로 검사하고, 처음 맞는 곳 하나만 실행하고 빠져나간다.
score 가 95 라면 첫 줄에서 A 를 찍고 끝난다. score >= 80 도 참이지만 쳐다보지 않는다. 그래서 범위를 검사할 때는 좁은 조건을 위에 둔다.
- score >= 90 ?참이면 A 를 찍고 끝
- score >= 80 ?여기까지 왔다면 90 미만이다
- else전부 아니면 여기
순서를 뒤집어 score >= 80 을 위에 두면, 95점도 B 가 된다. 90점 이상은 영원히 도달하지 못한다.
중괄호를 생략하면
if 뒤에 문장이 하나뿐이면 중괄호를 뺄 수 있다.
if (score >= 90)
System.out.println("A");
되긴 되는데, 이런 일이 생긴다.
if (score >= 90)
System.out.println("A");
System.out.println("축하한다");
들여쓰기를 보면 둘 다 조건 안에 있는 것 같다. 하지만 중괄호가 없으면 바로 다음 한 문장까지만 조건에 걸린다. 축하한다 는 점수와 상관없이 언제나 찍힌다.
컴파일러는 들여쓰기를 읽지 않는다. 중괄호는 항상 쓴다. 한 줄이어도 쓴다.
삼항 연산자 — 값을 고르는 if
if 는 문장이라 값을 돌려주지 못한다. 값을 고르고 싶을 때는 물음표를 쓴다.
int score = 85;
String grade = score >= 60 ? "합격" : "불합격";
System.out.println(grade);
- 합격
조건 ? 참일 때 : 거짓일 때 로 읽는다.
짧은 판단에만 쓴다. 삼항 연산자를 두세 개 겹치기 시작하면 그때부터는 if 가 낫다.
&& 와 || 는 게으르다
5강에서 잠깐 언급했던 성질을 이제 써먹는다.
String name = null;
if (name != null && name.length() > 3) {
System.out.println("긴 이름");
}
name 이 null 이니 name.length() 를 부르면 4강에서 본 NullPointerException 이 난다. 그런데 이 코드는 멀쩡히 돈다.
&& 는 왼쪽이 false 면 오른쪽을 아예 실행하지 않는다. 결과가 이미 false 로 정해졌기 때문이다.
switch — 값 하나를 여러 갈래로
같은 변수를 여러 값과 비교할 때는 switch 가 읽기 좋다.
옛날 방식부터 본다. 여기에 자바의 유명한 함정이 하나 있다.
int day = 2;
switch (day) {
case 1: System.out.println("월");
case 2: System.out.println("화");
case 3: System.out.println("수");
default: System.out.println("그 외");
}
day 가 2 니까 화 만 나와야 할 것 같다.
- 화
- 수
- 그 외
case 2 를 찾아 들어간 뒤, 거기서 멈추지 않고 아래로 계속 흘러내린다. 이걸 폴스루라고 부른다.
멈추려면 break 를 적어야 한다.
switch (day) {
case 1: System.out.println("월"); break;
case 2: System.out.println("화"); break;
default: System.out.println("그 외");
}
화살표 switch — 폴스루가 없다
자바 14 부터 화살표를 쓸 수 있다. break 가 필요 없고, 흘러내리지도 않는다.
int day = 2;
switch (day) {
case 1 -> System.out.println("월");
case 2 -> System.out.println("화");
default -> System.out.println("그 외");
}
- 화
한 줄만 실행하고 끝난다. 새 코드에서는 이쪽을 쓴다.
여러 값을 묶으려면 쉼표로 나열한다.
switch (day) {
case 6, 7 -> System.out.println("주말");
default -> System.out.println("평일");
}
switch 가 값을 돌려준다
화살표 switch 는 값을 만들어내는 표현식으로도 쓸 수 있다.
int day = 2;
String name = switch (day) {
case 1 -> "월";
case 2 -> "화";
default -> "?";
};
System.out.println(name);
- 화
마지막 중괄호 뒤에 세미콜론이 붙는 것에 주의하자. 이건 문장이 아니라 값이라서 그렇다. int x = 3; 의 세미콜론과 같은 자리다.
이렇게 쓰면 default 를 빼먹을 수 없다. 값을 돌려줘야 하는데 아무 case 에도 안 걸리면 줄 게 없기 때문이다. 컴파일러가 막아준다.
콜론 switch
case 1: … break;
break를 빠뜨리면 아래로 흘러내린다- 값을 돌려주지 못한다
- 옛 코드에서 계속 만난다
- 읽을 줄은 알아야 한다
화살표 switch
case 1 -> …
- 흘러내리지 않는다.
break가 없다 - 값을 돌려줄 수 있다
case 6, 7 ->로 묶을 수 있다- 자바 14 이상. 새 코드는 이걸 쓴다
switch 는 문자열을 어떻게 비교하나
switch 에는 문자열도 넣을 수 있다. 그런데 6강에서 문자열은 == 로 비교하면 안 된다고 했다. switch 는 어느 쪽일까.
직접 확인해보자. new String 으로 만들어서 == 가 false 인 것을 먼저 확인한다.
String s = new String("apple");
System.out.println(s == "apple");
switch (s) {
case "apple" -> System.out.println("switch 가 잡았다");
default -> System.out.println("못 잡았다");
}
- false
- switch 가 잡았다
== 로는 false 인데 switch 는 잡아냈다. switch 는 내부적으로 .equals() 를 쓴다.
다행이지만, 여기에도 함정이 있다.
String s = null;
switch (s) {
case "apple" -> System.out.println("사과");
default -> System.out.println("그 외");
}
- Exception in thread "main" java.lang.NullPointerException
default 로 가주지 않는다. null 은 .equals() 를 부를 대상이 아니기 때문이다. switch 에 넣기 전에 null 을 걸러야 한다.
4강에서 null 이 조용히 흘러 들어온다고 했던 게 이런 뜻이다.
정리하면
자바의 if 는 boolean 만 받고, switch 는 화살표를 쓰면 값까지 돌려준다.
- 01
if에는boolean만 들어간다if (score = 90)은 컴파일 에러다. 다른 언어의 고전적인 버그를 언어가 막는다. - 02
중괄호는 언제나 쓴다
컴파일러는 들여쓰기를 읽지 않는다.
- 03
&&는 왼쪽이 거짓이면 오른쪽을 보지 않는다null 검사를 왼쪽에 두면 오른쪽이 보호받는다.
if (name != null && name.length() > 3) { ... } - 04
콜론
switch는 흘러내린다break 를 빠뜨리면 아래 case 까지 실행된다. 컴파일러는 잡아주지 않는다.
- 05
화살표
switch를 쓴다흘러내리지 않고, 값을 돌려줄 수 있다.
String name = switch (day) { case 1 -> "월"; default -> "?"; }; - 06
switch는 문자열을.equals()로 비교한다다만 null 을 넣으면 NullPointerException 이 난다.
이제 길을 나눌 줄 안다. 다음 강의에서는 같은 길을 여러 번 걷는다.
반복문에는 세 가지가 있는데, 자바에는 그중 하나가 좀 특이하게 생겼다. 콜론이 하나 들어간다. 그리고 그걸 쓰려면 9강의 배열이 있어야 한다.