Java 13

if, else, else if로 조건 흐름 나누기: 왜 한 번만 실행될까?

if와 else if를 여러 개 쓰면 위에서 아래로 어떤 조건이 먼저 잡히고 어떤 코드는 건너뛰는지 흐릿하다.

근거 · 교안 p95-p102

if, else, else if로 조건 흐름 나누기: 왜 한 번만 실행될까? 대표 이미지

1장: if와 if-else: ‘선택’의 첫 단추

솔라는 모니터에 떠 있는 코드 조각을 보며 미간을 찌푸렸다. 날씨에 따라 옷차림을 추천해 주는 간단한 프로그램을 짜보던 중이었다. 분명 간단한 규칙 몇 개를 옮긴 것뿐인데, 어쩐지 결과가 마음에 들지 않았다.

“언니, 잠깐 이것 좀 봐줄래?”

솔라의 부름에 루나가 다가와 모니터 옆에 섰다. 솔라가 가리킨 코드는 이랬다.

let temperature = 18;

if (temperature < 25) {
  console.log("조금 쌀쌀할 수 있으니, 얇은 겉옷을 챙기세요.");
}
if (temperature < 15) {
  console.log("쌀쌀한 날씨! 따뜻한 옷을 입으세요.");
}

temperature가 18일 때는 첫 번째 메시지만 나오는 게 맞아. 그런데 만약 10이 되면 메시지가 두 개 다 나와.”

솔라가 말했다.

“그게 틀린 건 아니지. 10도는 25도보다도 작고, 15도보다도 작으니까. 그런데… 느낌이 이상해. 마치 컴퓨터가 모든 가능성을 하나하나 다 말해주는 것 같달까. 나는 딱 맞는 추천 하나만 받고 싶은데.”

솔라는 잠시 고민하더니 말을 이었다.

“조건문은 ‘조건에 따라 실행할 코드를 선택하는 문법’이라고 배웠어. 그런데 지금 이건 선택이라기보다, 그냥 맞는 건 전부 실행하는 느낌이야. if-else를 쓰면 좀 다르려나? 근데 그것도 결국 if (조건)이랑 if (!조건)을 쓰는 거랑 비슷하지 않아?”

솔라의 생각은 명료했다. 여러 개의 if문은 그냥 순서대로 검사하는 목록일 뿐이고, if-else는 그 목록을 쓰는 약간 다른 표현법일 뿐이라는 것.

루나는 고개를 끄덕이며 솔라의 말을 들었다. 그리고는 솔라가 짠 코드 옆에 새로운 편집기 창을 하나 더 열었다.

“선택이라는 말이 헷갈리게 한 것 같네. 두 가지 코드를 비교해 보자. 네가 말한 ‘선택’의 의미가 어떻게 다른지 보일 거야.”

루나는 첫 번째 창에는 성적에 따라 등급을 매기는 코드를, 두 번째 창에는 비슷한 역할을 하지만 구조가 다른 코드를 작성했다.

코드 A

let score = 95;

if (score >= 90) {
  console.log("A 등급입니다.");
}
if (score >= 80) {
  console.log("B 등급 이상입니다.");
}

코드 B

let score = 95;

if (score >= 90) {
  console.log("A 등급입니다.");
} else {
  console.log("A 등급이 아닙니다.");
}

“자, score가 95일 때 각각 어떤 결과가 나올까?”

솔라는 코드 A를 먼저 손가락으로 짚으며 따라갔다. “첫 번째 if문. 95는 90보다 크거나 같으니까 ‘A 등급입니다.‘가 출력될 거야. 그리고… 다음 if문으로 가겠지. 95는 80보다도 크거나 같으니까 ‘B 등급 이상입니다.‘도 출력되겠네. 두 줄이 다 나오겠다.”

마치 자신의 옷차림 추천 프로그램처럼, 해당하는 모든 조건이 실행될 것이라는 예측이었다.

“좋아. 그럼 코드 B는?”

“음… 95는 90보다 크거나 같으니까, ‘A 등급입니다.‘가 출력되고… 그리고 else는… if 조건이 거짓일 때 실행되는 거니까… 여긴 실행이 안 되겠네. 그럼 ‘A 등급입니다.’ 한 줄만 나오겠다.”

솔라는 자신 있게 대답했지만, 무언가 깨달은 듯 잠시 말을 멈췄다. 두 코드의 결과가 다르다는 사실이 그녀의 머릿속에 작은 파문을 일으켰다.

“결과가 다르네.”

루나가 그 간격을 파고들었다. “왜 다를까? 컴퓨터가 두 코드를 실행하는 과정을 생각해 봐. 코드 A에서는 첫 번째 if문의 일이 끝나고 나서 뭘 하지?”

“두 번째 if문으로 넘어가서, 조건을 또 검사해요.”

“맞아. 두 개의 if문은 서로 완전히 독립적이야. 별개의 질문 두 개를 던지는 것과 같지. ‘90점 이상인가요?‘라고 묻고 답을 한 뒤, ‘80점 이상인가요?‘라고 새로 묻는 거야.”

솔라는 고개를 끄덕였다. 그건 그녀가 처음 생각했던 방식 그대로였다.

“그럼 코드 B는?” 루나가 물었다. “첫 번째 if문에서 ‘90점 이상인가요?‘라고 물었어. 답은 ‘예’였지. 그래서 ‘A 등급입니다.‘라고 출력했어. 그다음은?”

“그다음은… else가 있으니까… 그냥 끝?” 솔라가 조심스럽게 대답했다.

“바로 그거야. if-else는 하나의 묶음이야. 갈림길과

2장: else if의 비밀: 순차 검사와 배타적 실행

”…갈림길과 같아. 둘 중 하나를 선택하면, 나머지 길은 아예 없는 셈 치는 거지.”

루나는 말을 마치며 키보드에 손을 올렸다. 솔라가 아까 짚었던, 두 개의 독립된 if문으로 이루어진 코드 A를 수정하기 시작했다. if문 하나가 else if로 바뀌고, 마지막엔 else까지 덧붙었다. 화면에는 이제 갈림길이 여러 개로 늘어난 듯한 새로운 코드가 나타났다.

let score = 85;

if (score >= 90) {
  console.log("A 등급입니다.");
} else if (score >= 80) {
  console.log("B 등급입니다.");
} else {
  console.log("C 등급 이하입니다.");
}

“자, 이제 이건 어떨까?” 루나가 물었다. “갈림길이 여러 개로 늘어난 셈이야. 점수가 85점일 때, 컴퓨터는 어떤 길을 선택할까?”

솔라는 새로운 코드를 유심히 들여다봤다. if-else가 하나의 묶음이라는 건 방금 막 깨달았다. 그렇다면 if-else if-else도 전부 한 덩어리일까?

“음… 일단 첫 번째 if문. 85는 90보다 크거나 같지 않으니까, 여긴 아니야. 그럼 다음으로 넘어가서… else if? else가 붙었으니 첫 번째 if가 거짓일 때만 검사하겠지. 85는 80보다 크거나 같으니까… 이 조건은 참이네! 그럼 ‘B 등급입니다.‘가 출력될 거야.”

거기까지는 확신에 차서 말했다. 하지만 솔라의 시선은 코드의 마지막 줄, else에 머물렀다.

“그런데… 여기서 끝나는 게 맞나? 아니면 혹시 모르니 마지막 else까지 확인하려나? if문들이 여러 개 있을 땐 맞는 걸 전부 다 실행했었잖아. 이것도 혹시…?”

솔라의 혼란은 명확했다. 조건이 참인 것을 발견한 뒤에도, 컴퓨터가 혹시 모를 다른 가능성을 계속 검사할지도 모른다는 의심이었다. if-else if 체인이 하나의 묶음인지, 아니면 그저 순서대로 연결된 별개의 검문소들인지 확신이 서지 않았다.

루나는 말없이 score의 값을 95로 바꿨다.

“자, 그럼 95점일 때는?”

“95점이면… 첫 번째 if문 조건, score >= 90이 바로 참이 되네. 그럼 ‘A 등급입니다.‘가 출력돼.” 솔라가 빠르게 대답했다. 그리고는 코드를 실행했다. 결과는 예상대로였다.

출력:

A 등급입니다.

이번엔 루나가 score를 다시 85로 바꾸었다.

“이건 아까 네가 예측했던 경우지. 직접 실행해 봐.”

솔라는 코드를 실행했고, 모니터에는 ‘B 등급입니다.‘라는 메시지만 나타났다.

출력:

B 등급입니다.

마지막으로 루나가 score를 75로 바꾸었다. 솔라는 잠시 생각하더니 말했다. “첫 번째 if도 거짓, 두 번째 else if도 거짓. 그럼 마지막 남은 else가 실행되겠네. ‘C 등급 이하입니다.‘가 나오겠지.”

실행 결과는 정확히 솔라의 예측과 일치했다. 솔라는 세 가지 다른 입력값과 그 결과를 나란히 보며 생각에 잠겼다. 95점일 때, ‘A 등급입니다.‘가 출력된 후 score >= 80이라는 조건은 검사조차 되지 않았다. 그 조건도 분명 참인데도 말이다.

그 순간, 솔라의 머릿속에서 조각들이 맞춰졌다.

“아! 알겠다. 이건 여러 개의 갈림길이 있는 게 아니라, 그냥 하나의 긴 미끄럼틀 같은 거였어!”

솔라가 손가락으로 코드의 맨 위부터 아래까지 쓸어내리며 말했다.

“맨 위에서부터 ‘이 조건 맞아?’ 하고 물어보는 거야. 아니면, 다음 칸으로 미끄러져 내려가. 거기서 또 ‘이 조건은?’ 하고 묻고. 그러다가 ‘맞아!’ 하는 칸을 만나면, 바로 그 칸에 있는 코드를 실행하고 미끄럼틀에서 그냥 빠져나와 버리는 거야. 그 아래에 뭐가 더 있든 전혀 신경 안 쓰고!”

if-else if-else 체인은 독립적인 질문들의 나열이 아니었다. 위에서 아래로 흐르는 단 하나의 물줄기였다. 첫 번째로 만나는 수문을 열고 빠져나가면, 그 아래의 다른 수문들은 열릴 기회조차 얻지 못하는 구조. ‘순서대로’ 검사하고, ‘하나만’ 실행하는 것이다.

루나는 솔라의 비유를 들으며 조용히 고개를 끄덕였다.

“미끄럼틀 비유, 괜찮네. 그럼 그 미끄럼틀에서 아주 중요한 규칙이 하나 있지 않을까?”

“규칙?”

“만약 내가 이 코드의 순서를 이렇게 바꾸면 어떻게 될까?”

루나는 score >= 90 조건과 score >= 80 조건의 순서를 맞바꾸었다.

let score = 95;

if (score >= 80) {
  console.log("B 등급입니다.");
} else if (score >= 90) {
  console.log("A 등급입니다.");
} else {
  console.log("C 등급 이하입니다.");
}

“어?” 솔라의 눈이 동그래졌다. “점수가 95점인데… 미끄럼틀을 타면, 첫 번째 조건인 score >= 80에서 바로 ‘참’이 되잖아? 그럼 ‘B 등급입니다.‘가 출력되고… 그냥 끝나버리겠네. 95점인데도 A 등급을 못 받아!”

솔라는 자신이 발견한 ‘순차적 검사, 배타적 실행’ 원리가 코드의 순서에 얼마나 민감하게 반응하는지 깨달았다. if문들을 각각 독립적으로 쓸 때는 순서가 중요하지 않을 수 있지만, if-else if라는 하나의 흐름으로 묶이는 순간, 조건의 순서는 코드의 논리를 결정하는 핵심 요소가 되었다.

“그럼… 내가 원하는 대로 컴퓨터가 움직이게 하려면, 이 조건들의 순서를 아주 신중하게 짜야 한다는 거네. 더 좁은 범위의 조건, 더 까다로운 조건을 먼저 물어봐야 하는구나.”

솔라는 이제 if-else if-else 구조가 어떻게 작동하는지 명확히 이해했다. 하지만 동시에 새로운 고민이 생겨났다. 머릿속의 논리를 올바른 순서의 조건문으로 바꾸는 것, 그것은 또 다른 차원의 문제처럼 느껴졌다.

3장: 완벽한 이해: if 계열 조건 흐름의 원리

솔라의 손가락이 키보드 위에서 망설였다. 화면에는 이전 장에서 순서를 바꾸었다가 논리가 엉켜버린 등급 계산 코드가 떠 있었다. 95점을 B 등급으로 판단해 버리는, 명백히 잘못된 코드였다.

“더 좁은 범위, 더 까다로운 조건을 먼저 물어봐야 한다…”

솔라는 혼잣말을 하며 코드에 새로운 줄을 추가하기 시작했다. score >= 80 조건이 score >= 90보다 먼저 나오는 문제를 해결하기 위해, 그 사이에 새로운 조건을 끼워 넣으면 어떨까 생각한 것이다. 하지만 코드는 나아지기는커녕 점점 더 복잡하고 기괴한 형태로 변해갔다. 그녀의 머릿속은 ‘순서대로 검사한다’, ‘하나만 실행된다’는 규칙과 ‘내가 원하는 대로 동작하게 만들고 싶다’는 목표 사이에서 길을 잃고 헤맸다. 규칙을 아는 것과 그 규칙을 사용해 원하는 결과를 만드는 것은 다른 문제였다.

“아직도 그거랑 씨름하고 있네.”

어느새 다가온 루나가 솔라의 모니터를 들여다보며 말했다. 화면에 떠 있는 코드는 누더기처럼 덧대어진 조건문들로 가득했다.

“원리는 알겠는데, 막상 이걸로 내가 원하는 논리를 만들려니까 확신이 안 서. 조건 순서가 중요하다는 건 알겠는데, 어떤 순서가 ‘올바른’ 순서인지 판단하기가 어려워. 그냥 감으로 때려 맞추는 기분이야.”

솔라의 목소리에는 답답함이 묻어났다. if-else if의 동작 원리를 이해한 기쁨은, 그것을 제대로 설계해야 한다는 새로운 압박감에 자리를 내주고 있었다.

루나는 잠시 생각하더니, 솔라가 짜던 코드 창을 옆으로 밀어두고 새 파일을 열었다.

“설계는 예측이랑은 조금 달라. 직접 한번 길을 만들어보자. 이번엔 쇼핑몰 할인 조건을 만들어 볼 거야.”

루나는 메모장처럼 쓸 수 있는 빈 곳에 몇 가지 규칙을 적었다.

  • VIP 회원은 구매 금액과 상관없이 20% 할인
  • VIP가 아니더라도, 10만 원 이상 구매 시 10% 할인
  • 위 조건에 해당하지 않는 첫 구매 고객은 5% 할인 쿠폰 지급

“자, 이 세 가지 규칙을 코드로 옮겨보자. if-else if-else 구조를 사용해서. 어떤 순서로 조건을 배치해야 할까?”

솔라는 잠시 규칙들을 뜯어보았다. 조건들이 서로 겹치는 부분이 보였다. VIP 회원이 10만 원 이상 구매할 수도 있고, 첫 구매 고객이 10만 원 이상 살 수도 있었다. 지난번 성적 코드에서 겪었던 순서의 중요성이 다시 한번 머리를 스쳤다.

“가장 까다로운 조건, 혹은 가장 특별한 조건을 먼저 처리해야 했어.” 솔라는 중얼거리며 코드를 입력하기 시작했다.

let isVIP = true;
let purchaseAmount = 120000;
let isFirstPurchase = false;

if (isVIP === true) {
  console.log("VIP 회원 20% 할인이 적용됩니다.");
} else if (purchaseAmount >= 100000) {
  console.log("10만원 이상 구매 10% 할인이 적용됩니다.");
} else if (isFirstPurchase === true) {
  console.log("첫 구매 5% 할인 쿠폰이 지급됩니다.");
}

“일단 이렇게 짜봤어. 가장 강력한 혜택인 VIP 할인을 맨 위에 뒀어.”

“좋아. 그럼 저 코드에서 isVIPtrue이고, purchaseAmount가 12만 원인 고객은 어떤 메시지를 받게 될까? 네가 만든 미끄럼틀을 직접 타봐.”

솔라는 자신의 코드 위를 손가락으로 짚으며 흐름을 따라갔다.

“맨 위, 첫 번째 if문에서 조건을 검사해. isVIPtrue인가? 응, true네.”

솔라의 손가락이 멈췄다.

“여기서 바로 ‘참’이 됐으니까… ‘VIP 회원 20% 할인’ 메시지가 출력될 거야. 그리고… 미끄럼틀에서 빠져나오겠지.”

“그다음 조건들은?”

“전혀 신경 쓰지 않아. purchaseAmount가 10만 원이 넘든 말든, 첫 구매든 아니든, 컴퓨터는 아예 쳐다보지도 않을 거야. 첫 관문에서 통과됐으니까.”

솔라는 말을 마치고 스스로 놀란 듯했다. 이전에는 컴퓨터가 모든 조건을 다 검사할지도 모른다고 막연히 의심했지만, 이제는 ‘검사조차 하지 않는다’고 확신에 차서 말할 수 있었다. 그 순간, 조건문의 순서가 가진 의미가 완전히 다르게 다가왔다.

이것은 단순히 더 좁은 조건을 먼저 쓰는 기술적인 문제가 아니었다. 이것은 ‘의도’의 문제였다. 프로그래머가 어떤 조건을 더 중요하게 생각하는지, 어떤 규칙을 다른 규칙보다 우선할 것인지를 컴퓨터에게 명확히 알려주는 선언과도 같았다. if-else if 체인의 순서는 논리의 우선순위를 그대로 반영하는 설계도였던 것이다.

“알겠다…!” 솔라가 무릎을 탁 쳤다. “조건의 순서를 정하는 건, 그냥 코드를 동작하게 만드는 게 아니라, 내가 ‘이 경우에는 다른 건 따지지 말고 이걸 최우선으로 해줘’라고 컴퓨터에게 명령하는 거였어. 정책을 정하는 거랑 똑같네.”

그녀는 이제 if, else if, else가 단순히 참/거짓에 따라 코드를 실행하는 문법이 아님을 깨달았다. 그것은 여러 갈래의 길 앞에서 어떤 길을 먼저 확인할지, 그리고 하나의 길을 선택했을 때 나머지 길은 돌아보지 않겠다는 ‘순차적이고 배타적인 선택의 흐름’ 그 자체였다. 조건문은 조건에 따라 실행할 코드를 선택하는 문법이다라는 처음의 문장이, 이제야 비로소 입체적인 의미로 다가왔다.

스스로의 깨달음에 고무된 솔라는 처음 자신이 씨름하던 문제로 돌아갔다. 날씨에 따라 옷차림을 추천하던, 두 개의 메시지가 모두 출력되어 그녀를 혼란스럽게 했던 바로 그 코드였다.

// 예전 코드
let temperature = 10;

if (temperature < 25) {
  console.log("조금 쌀쌀할 수 있으니, 얇은 겉옷을 챙기세요.");
}
if (temperature < 15) {
  console.log("쌀쌀한 날씨! 따뜻한 옷을 입으세요.");
}

솔라는 망설임 없이 코드를 지우고 새로 작성하기 시작했다. 이제 그녀의 손가락은 헤매지 않았다. 어떤 순서가 올바른 순서인지 명확히 알고 있었다.

// 새로 작성한 코드
let temperature = 10;

if (temperature < 15) {
  console.log("쌀쌀한 날씨! 따뜻한 옷을 입으세요.");
} else if (temperature < 25) {
  console.log("조금 쌀쌀할 수 있으니, 얇은 겉옷을 챙기세요.");
} else {
  console.log("따뜻한 날씨네요!");
}

새로운 코드는 깔끔하고 명료했다. 솔라는 코드를 보며 만족스러운 미소를 지었다.

“이제 온도가 10도면, 가장 좁은 범위인 15도 미만 조건에 바로 걸려서 ‘따뜻한 옷’ 메시지만 나오고 끝이야. 18도라면 첫 번째 조건은 건너뛰고, 두 번째 else if에서 걸려서 ‘얇은 겉옷’ 메시지가 나오겠지. 이제야 비로소 컴퓨터가 내 의도대로 ‘선택’을 하고 있어.”

솔라는 더 이상 조건문의 흐름을 예측하기 위해 애쓰지 않았다. 대신, 자신이 원하는 흐름을 직접 설계하고 있었다. 그것은 작은 변화였지만, 그녀에게는 커다란 도약이었다.