Skip to main content

연산자·조건문·반복문으로 프로그램 흐름 제어하기

프로그램은 결국 "상황을 판단하고, 그에 따라 행동을 바꾸는 일"의 연속이다. 컴퓨터는 스스로 눈치껏 움직이지 않는다. 개발자가 연산자로 값을 계산해 주고, 조건문으로 갈림길을 만들어 주고, 반복문으로 같은 일을 여러 번 시켜야 한다. 이 장은 바로 그 핵심을 다룬다.

앞 장에서 변수와 자료형, 기본적인 문장 작성법을 익혔다면 이제는 프로그램에 "생각하는 흐름"을 넣을 차례다. 사용자가 입력한 점수에 따라 합격 여부를 판단하고, 메뉴 번호에 따라 다른 동작을 수행하며, 같은 작업을 100번 반복하게 만드는 것이 바로 흐름 제어다. 이 장을 잘 이해하면 문제를 코드로 바꾸는 감각이 한층 또렷해진다.

연산자·조건문·반복문으로 프로그램 흐름 제어하기

흐름 제어란 무엇일까

흐름 제어는 프로그램이 어떤 순서로 실행될지를 결정하는 방법이다. 아무 제어도 없다면 코드는 위에서 아래로 한 줄씩 실행된다. 하지만 실제 프로그램은 늘 선택과 반복이 필요하다.

예를 들어 보자. 쇼핑몰 프로그램은 다음과 같은 판단을 해야 한다.

  • 장바구니 금액이 5만 원 이상이면 배송비를 무료로 할까?

  • 로그인한 사용자인가?

  • 재고가 남아 있는가?

  • 같은 상품을 여러 개 처리해야 하는가?

이런 문제를 풀기 위해 사용하는 도구가 연산자, 조건문, 반복문이다. 세 가지는 각각 역할이 조금 다르다. 연산자는 값을 계산하고 비교한다. 조건문은 "이럴 때는 이렇게, 저럴 때는 저렇게"를 결정한다. 반복문은 같은 작업을 필요한 만큼 반복한다.

연산자: 값을 계산하고 비교하는 도구

연산자는 데이터를 다루는 가장 기본적인 도구다. 숫자를 더하거나, 값을 비교하거나, 조건을 조합할 때 사용한다. 흐름 제어는 결국 조건을 판단하는 일인데, 조건을 만들려면 연산자를 알아야 한다.

산술 연산자

가장 익숙한 연산자다. 숫자를 계산할 때 사용한다.

  • + : 더하기

  • - : 빼기

  • * : 곱하기

  • / : 나누기

  • % : 나머지

다음 예제를 보자.

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 3;

        System.out.println(a + b); // 13
        System.out.println(a - b); // 7
        System.out.println(a * b); // 30
        System.out.println(a / b); // 3
        System.out.println(a % b); // 1
    }
}

여기서 중요한 점은 int / int의 결과도 int라는 것이다. 즉 10 / 3은 3.333...이 아니라 3이 된다. 소수점까지 필요하면 double을 사용해야 한다.

double result = 10.0 / 3.0;
System.out.println(result); // 3.3333333333333335

% 연산자는 생각보다 자주 쓰인다. 어떤 수가 짝수인지 홀수인지 판별할 때 특히 유용하다.

int number = 7;
System.out.println(number % 2); // 1

나머지가 0이면 짝수, 1이면 홀수다.

대입 연산자와 복합 대입 연산자

대입 연산자 =는 오른쪽 값을 왼쪽 변수에 저장한다.

int score = 90;

복합 대입 연산자는 계산과 대입을 한 번에 처리한다.

  • +=

  • -=

  • *=

  • /=

  • %=

int x = 10;
x += 5;  // x = x + 5
x *= 2;  // x = x * 2
System.out.println(x); // 30

코드를 짧게 만드는 데 도움이 되지만, 너무 복잡한 식에 섞어 쓰면 오히려 읽기 어려워질 수 있다.

증가 연산자와 감소 연산자

++는 1 증가, --는 1 감소를 의미한다.

int count = 0;
count++;
count++;
count--;
System.out.println(count); // 1

이 연산자는 반복문에서 매우 자주 등장한다. 다만 앞에 붙는지 뒤에 붙는지에 따라 동작 시점이 달라진다.

int a = 5;
int b = ++a; // 먼저 증가, 그다음 대입
System.out.println(a); // 6
System.out.println(b); // 6

int c = 5;
int d = c++; // 먼저 대입, 그다음 증가
System.out.println(c); // 6
System.out.println(d); // 5

처음에는 헷갈릴 수 있다. 복잡한 문장 안에서 전위 증가와 후위 증가를 섞기보다, 필요하면 한 줄로 분리해서 쓰는 습관이 안전하다.

비교 연산자

비교 연산자는 두 값을 비교해서 true 또는 false를 만든다. 조건문은 이 참과 거짓을 바탕으로 움직인다.

  • == : 같다

  • != : 같지 않다

  • > : 크다

  • < : 작다

  • >= : 크거나 같다

  • <= : 작거나 같다

int age = 20;
System.out.println(age >= 19); // true
System.out.println(age < 19);  // false

여기서 =와 ==를 꼭 구분해야 한다. =는 저장, ==는 비교다. 초보자가 가장 자주 하는 실수 중 하나다.

논리 연산자

논리 연산자는 여러 조건을 조합할 때 사용한다.

  • && : 그리고(AND)

  • || : 또는(OR)

  • ! : 아니다(NOT)

int age = 22;
boolean hasId = true;

System.out.println(age >= 19 && hasId); // true
System.out.println(age < 19 || hasId);  // true
System.out.println(!hasId);             // false

예를 들어 성인이고 신분증도 있어야 입장 가능한 상황이라면 &&를 쓴다. 둘 중 하나만 만족해도 되는 경우는 ||를 쓴다.

논리 연산자의 짧은 평가

자바의 &&와 ||는 왼쪽 조건만으로 결과가 결정되면 오른쪽 조건을 검사하지 않는다. 이를 짧은 평가라고 한다.

int x = 10;

if (x > 0 && x < 100) {
    System.out.println("1부터 99 사이의 수입니다.");
}

첫 번째 조건이 거짓이면 뒤를 굳이 볼 필요가 없다. 이런 특성은 성능 면에서도 유리하고, 때로는 오류를 막아 주기도 한다.

문자열 연결에도 쓰이는 +

+는 숫자끼리 쓰면 덧셈이지만, 문자열과 함께 쓰이면 이어 붙이기가 된다.

String name = "JAVA";
int version = 21;
System.out.println(name + " " + version);

출력 결과는 JAVA 21이다. 다만 숫자 계산과 문자열 연결이 섞이면 결과가 예상과 다를 수 있다.

System.out.println(1 + 2 + "3"); // 33
System.out.println("1" + 2 + 3); // 123

앞에서부터 차례로 계산된다는 점을 기억하자.

연산자 우선순위는 괄호로 이기자

연산자마다 우선순위가 있지만, 처음에는 전부 외우려 하지 않아도 된다. 중요한 계산은 괄호로 묶으면 된다.

int result = (3 + 5) * 2;
System.out.println(result); // 16

코드는 컴퓨터만 읽는 것이 아니다. 미래의 나와 다른 사람도 읽는다. 괄호는 친절함이다.

조건문: 갈림길을 만드는 법

조건문은 프로그램에 선택지를 만들어 준다. 같은 입력이라도 상황에 따라 다른 결과를 내게 해 준다. 대표적으로 if와 switch가 있다.

if문: 가장 기본적인 선택

if문은 조건이 참일 때만 특정 코드를 실행한다.

int score = 85;

if (score >= 80) {
    System.out.println("합격입니다.");
}

조건이 참이면 중괄호 안이 실행되고, 거짓이면 건너뛴다.

if-else문: 둘 중 하나 선택하기

조건이 참일 때와 거짓일 때를 나누고 싶다면 else를 사용한다.

int score = 75;

if (score >= 80) {
    System.out.println("합격입니다.");
} else {
    System.out.println("불합격입니다.");
}

이제 프로그램은 두 갈래 길을 갖게 된다.

if-else if-else문: 여러 경우 나누기

점수에 따라 학점을 나누려면 조건이 둘보다 많아진다. 이럴 때 else if를 사용한다.

int score = 87;

if (score >= 90) {
    System.out.println("A 학점");
} else if (score >= 80) {
    System.out.println("B 학점");
} else if (score >= 70) {
    System.out.println("C 학점");
} else {
    System.out.println("재도전!");
}

위 코드는 위에서 아래로 검사한다. score가 87이면 첫 조건은 거짓, 두 번째 조건은 참이므로 B 학점이 출력되고 나머지는 검사하지 않는다.

조건의 순서는 매우 중요하다. 범위가 넓은 조건을 먼저 쓰면 뒤의 조건이 도달하지 못할 수 있다.

int score = 95;

if (score >= 60) {
    System.out.println("합격");
} else if (score >= 90) {
    System.out.println("우수 합격");
}

이 코드는 95점이어도 첫 번째 조건이 먼저 참이 되어 합격만 출력된다. 더 구체적인 조건을 먼저 써야 한다.

중첩 if문: 조건 안에 또 조건

조건문 안에 조건문을 넣을 수도 있다. 다만 너무 깊어지면 읽기 어려워진다.

int age = 20;
boolean hasTicket = true;

if (age >= 19) {
    if (hasTicket) {
        System.out.println("입장 가능합니다.");
    } else {
        System.out.println("티켓이 필요합니다.");
    }
} else {
    System.out.println("성인만 입장 가능합니다.");
}

이런 코드는 논리상 자연스럽지만, 복잡해질수록 조건을 합쳐 쓰는 편이 더 읽기 좋을 때도 있다.

if (age >= 19 && hasTicket) {
    System.out.println("입장 가능합니다.");
}

switch문: 값에 따라 분기하기

switch문은 하나의 값을 기준으로 여러 경우를 나눌 때 유용하다. 메뉴 번호, 등급 문자, 명령어 처리 같은 상황에서 읽기 쉽다.

int menu = 2;

switch (menu) {
    case 1:
        System.out.println("아메리카노");
        break;
    case 2:
        System.out.println("라떼");
        break;
    case 3:
        System.out.println("주스");
        break;
    default:
        System.out.println("없는 메뉴입니다.");
}

case는 경우를 의미하고, default는 어느 경우에도 해당하지 않을 때 실행된다.

여기서 핵심은 break다. break가 없으면 다음 case로 계속 흘러간다.

int menu = 1;

switch (menu) {
    case 1:
        System.out.println("아메리카노");
    case 2:
        System.out.println("라떼");
    default:
        System.out.println("주문 종료");
}

위 코드는 menu가 1일 때 아메리카노, 라떼, 주문 종료가 모두 출력된다. 이런 현상을 보통 폴스루(fall-through) 라고 부른다. 의도한 경우가 아니라면 break를 꼭 넣자.

switch는 언제 쓰면 좋을까

if와 switch 중 무엇을 써야 할지 고민될 수 있다. 기준은 단순하다.

  • 범위 비교나 복잡한 조건은 if

  • 하나의 값이 여러 경우 중 어디에 속하는지 고르는 일은 switch

예를 들어 score >= 90 같은 범위 조건은 if가 적합하다. 반면 month == 1, month == 2, month == 3처럼 같은 변수의 값을 여러 개와 비교하는 상황은 switch가 잘 어울린다.

반복문: 같은 일을 여러 번 시키기

반복문은 코드의 노동력을 크게 줄여 준다. 같은 문장을 10번 쓰는 대신 한 번만 쓰고 10번 반복하게 만들 수 있다.

자바의 대표적인 반복문은 for와 while이다.

for문: 반복 횟수가 보일 때

for문은 반복 횟수가 비교적 분명할 때 자주 사용한다.

for (int i = 1; i <= 5; i++) {
    System.out.println(i);
}

이 코드는 1부터 5까지 출력한다. 구조를 나눠 보면 다음과 같다.

  • int i = 1 : 시작값

  • i <= 5 : 반복 조건

  • i++ : 반복할 때마다 변화시키는 식

즉, i를 1로 시작해서 5 이하인 동안 1씩 증가시키며 반복한다는 뜻이다.

for문의 실행 순서 이해하기

for문은 처음 보면 한 줄에 너무 많은 정보가 담겨 있어서 낯설다. 하지만 실제 동작은 단순하다.

  1. 시작값을 만든다.

  2. 조건을 검사한다.

  3. 참이면 본문을 실행한다.

  4. 증감식을 실행한다.

  5. 다시 조건을 검사한다.

이 흐름만 머릿속에 있으면 for문이 훨씬 편해진다.

누적 계산은 반복문의 대표 연습 문제

반복문은 합계 계산에 자주 쓰인다.

int sum = 0;

for (int i = 1; i <= 10; i++) {
    sum += i;
}

System.out.println(sum); // 55

이 코드는 1부터 10까지의 합을 구한다. 핵심은 sum이라는 누적 변수를 만들어 매 반복마다 값을 더해 주는 것이다.

while문: 조건이 중심일 때

while문은 "몇 번 반복할지"보다 "언제까지 반복할지"가 중요할 때 적합하다.

int count = 1;

while (count <= 5) {
    System.out.println(count);
    count++;
}

이 코드도 1부터 5까지 출력한다. for문과 결과는 같지만 표현 방식이 다르다. while은 조건이 먼저 보이기 때문에, 특정 상태가 유지되는 동안 반복한다는 느낌이 강하다.

while문에서 가장 조심할 점: 무한 반복

while문은 조건이 계속 참이면 끝나지 않는다.

int count = 1;

while (count <= 5) {
    System.out.println(count);
}

위 코드는 count가 변하지 않으므로 조건이 계속 참이다. 이런 상태를 무한 반복이라고 한다. 반복문을 만들 때는 반드시 "언젠가 조건이 거짓이 되도록" 변수를 변화시켜야 한다.

for와 while의 선택 기준

둘 다 반복문이므로 어느 쪽으로도 대부분의 문제를 풀 수 있다. 하지만 읽기 쉬운 쪽을 선택하는 것이 좋다.

  • 1부터 100까지 반복처럼 횟수가 분명하면 for

  • 입력이 올 때까지 반복처럼 종료 시점이 조건에 달려 있으면 while

  • 초기값, 조건식, 증감식이 한눈에 보이면 for

  • 반복 중 변수 변화가 더 복잡하면 while

좋은 코드는 정답인 코드이면서 동시에 읽기 쉬운 코드다.

중첩 반복문: 반복 안의 반복

반복문 안에 또 반복문을 넣으면 여러 줄의 패턴이나 표를 만들 수 있다.

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 2; j++) {
        System.out.println("i=" + i + ", j=" + j);
    }
}

실행 순서를 따라가 보면 바깥 반복문이 한 번 돌 때마다 안쪽 반복문이 전부 실행된다. 처음에는 복잡해 보이지만, 표를 그리듯 생각하면 이해가 쉽다.

break: 반복을 즉시 끝내기

break는 현재 반복문을 즉시 종료한다. 조건을 만족하면 더 이상 반복할 필요가 없을 때 사용한다.

for (int i = 1; i <= 10; i++) {
    if (i == 5) {
        break;
    }
    System.out.println(i);
}

이 코드는 1, 2, 3, 4까지만 출력하고 끝난다. i가 5가 되는 순간 반복문 자체를 빠져나온다.

검색처럼 "찾으면 끝"인 문제에서 특히 유용하다.

int target = 7;
boolean found = false;

for (int i = 1; i <= 10; i++) {
    if (i == target) {
        found = true;
        break;
    }
}

System.out.println(found);

continue: 이번만 건너뛰고 다음 반복으로

continue는 반복문을 끝내지는 않고, 현재 반복만 건너뛴 뒤 다음 반복으로 넘어간다.

for (int i = 1; i <= 5; i++) {
    if (i == 3) {
        continue;
    }
    System.out.println(i);
}

출력 결과는 1, 2, 4, 5다. i == 3일 때만 아래 코드를 실행하지 않고 다음 차례로 넘어간다.

짝수만 출력하는 예제도 자주 나온다.

for (int i = 1; i <= 10; i++) {
    if (i % 2 != 0) {
        continue;
    }
    System.out.println(i);
}

홀수는 건너뛰고 짝수만 출력한다.

break와 continue의 차이

둘은 비슷해 보여도 역할이 완전히 다르다.

  • break는 반복문 자체를 종료한다.

  • continue는 현재 차례만 건너뛴다.

이 차이를 분명히 이해해야 흐름을 정확하게 제어할 수 있다.

조건문과 반복문을 함께 쓰면 프로그램이 살아난다

실제 문제는 연산자만으로도, 조건문만으로도, 반복문만으로도 풀리지 않는다. 보통은 세 가지를 함께 사용한다.

다음은 1부터 20까지 숫자 중 3의 배수만 출력하는 예제다.

for (int i = 1; i <= 20; i++) {
    if (i % 3 == 0) {
        System.out.println(i);
    }
}

반복문이 숫자를 차례로 만들고, % 연산자가 나머지를 계산하고, if문이 출력 여부를 결정한다. 이것이 바로 흐름 제어의 협업이다.

문제를 코드로 바꾸는 사고 순서

초보자는 문법보다 "어떻게 생각해야 할지"에서 더 자주 막힌다. 흐름 제어 문제를 만나면 다음 순서로 접근해 보자.

1단계: 무엇을 반복해야 하는가

숫자를 여러 번 검사해야 하는지, 배열의 요소를 차례로 봐야 하는지, 조건이 만족될 때까지 계속해야 하는지를 먼저 본다. 반복이 필요하면 for인지 while인지 결정한다.

2단계: 무엇을 판단해야 하는가

반복 중에 특정 조건을 검사해야 하는지 정리한다. 합격 여부, 짝수 여부, 종료 조건처럼 참과 거짓이 나뉘는 부분을 찾는다.

3단계: 어떤 값이 계속 바뀌는가

반복문은 보통 값의 변화가 함께 있어야 한다. i가 1씩 증가하는지, 카운트가 줄어드는지, 합계가 누적되는지 확인한다.

4단계: 언제 멈춰야 하는가

반복은 반드시 끝이 있어야 한다. 조건이 거짓이 되는 시점, 혹은 break로 빠져나오는 시점을 분명하게 해야 한다.

이 네 단계를 차례대로 생각하면 코드를 훨씬 차분하게 설계할 수 있다.

실전 예제 1: 비밀번호 3번 기회라고 상상해 보기

입력을 아직 배우지 않았더라도, 변수만으로 흐름을 설계하는 연습은 충분히 할 수 있다.

String correctPassword = "java123";
String inputPassword = "java123";
int chance = 3;

if (inputPassword.equals(correctPassword)) {
    System.out.println("로그인 성공");
} else {
    chance--;
    System.out.println("로그인 실패. 남은 기회: " + chance);
}

여기서는 조건문이 성공과 실패를 나누고, 실패했을 때는 감소 연산이 함께 일어난다. 프로그램은 단순해 보여도 이미 논리 구조를 갖고 있다.

실전 예제 2: 구구단의 시작

반복문을 배우면 가장 먼저 떠오르는 고전 예제가 구구단이다.

int dan = 3;

for (int i = 1; i <= 9; i++) {
    System.out.println(dan + " x " + i + " = " + (dan * i));
}

여기에는 산술 연산자, 문자열 연결, 반복문이 모두 들어 있다. 흐름 제어는 이런 식으로 조금씩 합쳐지며 강해진다.

실전 예제 3: 합격자 수 세기

여러 학생의 점수를 검사하며 합격자 수를 세는 상황을 생각해 보자.

int[] scores = {95, 67, 80, 72, 59};
int passCount = 0;

for (int i = 0; i < scores.length; i++) {
    if (scores[i] >= 70) {
        passCount++;
    }
}

System.out.println("합격자 수: " + passCount);

배열은 다음 장에서 더 자세히 배우겠지만, 여기서는 "여러 값을 반복하며 검사할 수 있다"는 감각만 익혀도 충분하다. 반복문은 대량의 데이터를 다룰 때 진가를 발휘한다.

자주 하는 실수

흐름 제어를 배우는 초반에는 실수가 아주 자연스럽다. 오히려 실수를 통해 구조를 더 잘 이해하게 된다.

  • =와 ==를 혼동한다.

  • if문의 조건 순서를 잘못 써서 뒤 조건이 실행되지 않는다.

  • while문에서 변수 값을 바꾸지 않아 무한 반복에 빠진다.

  • switch문에서 break를 빼먹는다.

  • continue와 break의 차이를 헷갈린다.

  • 중괄호를 생략하다가 의도와 다른 실행 흐름을 만든다.

특히 초보 단계에서는 한 줄짜리 if나 반복문이라도 중괄호를 생략하지 않는 편이 좋다. 보기에는 조금 길어져도 실수를 줄이는 데 큰 도움이 된다.

읽기 좋은 조건문을 만드는 팁

조건문은 맞게만 쓰는 것보다 읽기 좋게 쓰는 것이 중요하다. 프로그램이 커질수록 가독성이 실력 차이를 만든다.

예를 들어 이런 코드가 있다고 해 보자.

if (!(age < 19)) {
    System.out.println("성인입니다.");
}

동작은 맞지만 한 번 더 생각해야 한다. 아래처럼 쓰는 편이 더 직관적이다.

if (age >= 19) {
    System.out.println("성인입니다.");
}

조건은 가능한 한 짧고 분명하게 쓰자. 사람의 머리는 컴파일러보다 게으르기 때문이다.

흐름 제어는 결국 문제 해결의 언어다

이 장의 문법은 단순해 보여도, 실제로는 프로그래밍 전체를 떠받치는 기둥이다. 계산하고, 비교하고, 선택하고, 반복하는 능력은 이후의 메서드, 객체지향, 컬렉션, 예외 처리까지 모든 주제의 바탕이 된다.

처음에는 if, for, while이 각각 따로 노는 것처럼 보일 수 있다. 하지만 문제를 하나씩 풀다 보면 이들이 자연스럽게 연결되기 시작한다. 예를 들어 "1부터 100까지 숫자 중 짝수의 합을 구하라"는 문제를 만나면, 머릿속에서 바로 이런 흐름이 떠오르게 된다.

먼저 1부터 100까지 반복한다. 각 숫자가 짝수인지 %로 확인한다. 짝수라면 합계 변수에 더한다. 마지막에 결과를 출력한다. 바로 이것이 프로그래밍적 사고다.

마무리

이번 장에서는 프로그램의 흐름을 움직이는 핵심 도구를 배웠다. 연산자는 값을 계산하고 비교하는 도구였고, if와 switch는 선택을 만드는 장치였으며, for와 while은 반복을 가능하게 해 주었다. break와 continue는 반복의 세밀한 방향 조절 장치였다.

중요한 것은 문법을 외우는 것보다, 어떤 상황에서 어떤 흐름이 필요한지 생각하는 힘이다. 조건이 필요한가, 반복이 필요한가, 언제 멈춰야 하는가를 차분히 따져 보는 습관이 문제 해결 능력을 키운다.

다음 장에서는 이 흐름 제어 위에 메서드, 배열, 문자열이라는 더 실용적인 도구를 얹게 된다. 이제 프로그램은 한 줄씩 실행되는 문장을 넘어, 조금 더 구조적이고 재사용 가능한 모습으로 성장하기 시작한다.

책 목록

처음부터 실무까지 단계별로 배우는 JAVA 학습

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기