[Java 21] (4) - statement

조건문

 

코드의 실행흐름은 기본적으로 위에서 아래로 한 문장씩 순차적으로 수행되지만, 때로는 조건에 따라 문장을 건너뛰고, 때로는 같은 문장을 반복해서 수행해야할 때가 있습니다. 이처럼 프로그램의 흐름(flow)을 바꾸는 역할을 하는 문장들을 '제어문(flow control statement)'이라고 합니다. 제어문에는 조건문과 반복문이 있습니다.

 

if문

 

if문 가장 기본적인 조건문이며, 다음과 같이 '조건식'과 '블럭{ }'으로 이루어져 있습니다.

if (조건식) {
    // 조건식이 참(true)일 때 수행될 문장
}

if문에 사용되는 조건식은 일반적으로 비교 연산자와 논리 연산자로 구성됩니다.

 

블럭{ } 안에는 보통 여러 문장을 넣지만, 한 문장만 넣거나 아무런 문장도 넣지 않을 수 있습니다. 만일 블럭 내의 문장이 하나뿐 일 때는 아래와 같이 괄호{ } 를 생략할 수 있습니다.

if (score > 60) System.out.println("합격");

 

if-else문

 

if문의 변형인 if-else문의 구조는 다음과 같습니다. 'else'의 뜻이 '그 밖의 다른'이므로 조건식의 결과가 참이 아닐 때, 즉 거짓(false)일 때 else블럭의 문장을 수행하라는 뜻입니다.

if (조건식) {
    // 조건식이 참(true)일 때 수행될 문장
} else {
    // 조건식이 거짓(false)일 때 수행될 문장
}

두 개의 if문을 사용하는 것보다, if-else문을 사용하는 것이 하나의 조건식은 계산하므로 더 효율적입니다.

 

if-else문 역시 블럭 내의 문장이 하나뿐인 경우 아래와 같이 괄호{ }를 생략할 수 있습니다.

if (input == 0)
    System.out.println("입력하신 숫자는 0입니다.");
else
    System.out.println("입력하신 숫자는 0이 아닙니다.");

 

if-else if문

 

경우의 수가 셋 이상인 경우, 한 문장에 여러 개의 조건식을 쓸 수 있는 'if-else if'문을 사용하면 됩니다.

if (조건식1) {
    // 조건식1의 연산 결과가 참일 때 수행될 문장
} else if (조건식2) {
    // 조건식2의 연산 결과가 참일 때 수행될 문장
} else if (조건식3) {
    // 조건식3의 연산 결과가 참일 때 수행될 문장
} else {
    // 위의 어느 조건식도 만족하지 않을 때 수행될 문장
}

여기에서 조건식2와 조건식3은 조건식1의 연산 결과가 거짓(false)일 때만 수행될 수 있기 때문에, else if문에서 조건식1의 결과가 거짓일 때라는 조건을 중복해서 사용할 필요가 없습니다.

 

중첩 if문

 

if문의 블럭 내에 또 다른 if문을 포함시키는 것이 가능하며 이것을 중첩 if문이라고 부릅니다. 이때 중첩의 횟수에는 거의 제한이 없습니다.

if (조건식1) {
    // 조건식1의 결과가 참일 때 수행될 문장
    if (조건식2) {
    	// 조건식1과 조건식2가 모두 참일 때 수행될 문장
    } else {
    	// 조건식1이 참이고, 조건식2가 거짓일 때 수행될 문장
    }
} else {
    // 조건식1이 거짓일 때 수행될 문장
}

 

중첩 if문에서는 괄호{ }의 생략에 더욱 조심해야 합니다.

위의 코드는 언뜻 보기에 else블럭이 바깥쪽의 if문에 속한 것처럼 보이지만, 괄호가 생략되었을 때 else블럭은 가까운 if문에 속한 것으로 간주되기 때문에 실제로는 안쪽 if문의 else블럭이 되어버립니다.

 

switch문

 

if문은 조건식의 결과가 참과 거짓, 두 가지 밖에 없기 때문에 경우의 수가 많아질수록 else-if를 계속 추가해야하므로 조건식이 많아져서 복잡해지고, 여러 개의 조건식을 계산해야하므로 처리시간도 많이 걸립니다.

 

이러한 if문과 달리 switch문은 단 하나의 조건식으로 많은 경우의 수를 처리할 수 있고, 표현도 간결해 알아보기 쉽습니다. 그래서 처리할 경우의 수가 많은 경우에는 if문보다는 switch문으로 작성하는 것이 좋습니다. 다만 switch문은 제약조건이 있기 때문에, 경우의 수가 많아도 어쩔 수 없이 if문으로 작성해야 하는 경우도 있습니다.

switch (조건식) {
    case 값1:
    	//조건식의 결과가 값1과 같은 경우 수행될 문장
    	break;
    case 값2:
        //조건식의 결과가 값2과 같은 경우 수행될 문장
        break;
    default:
    	//조건식의 결과와 일치하는 case문이 없을 때 수행될 문장
}

default문의 경우 if문의 else블럭과 같은 역할을 하며, 그 위치는 어디라도 상관없으나 보통 마지막에 놓기 때문에 break문을 사용하지 않아도 됩니다.

 

break문은 각 case문의 영역을 구분하는 역할을 하는데, 만일 break문을 생략하면 case문 사이의 구분이 없어지므로 다른 break문을 만나거나, switch문 블럭{ }의 끝을 만날 때까지 나오는 모든 문장을 수행하게 됩니다. 이러한 이유로 각 case문의 마지막에 break문을 빼먹는 실수를 하지 않도록 주의해야 합니다.

 

그러나 경우에 따라서는 다음과 같이 고의적으로 break을 생략하는 경우도 있습니다.

switch (level) {
    case 3:
    	grantDelete();
    case 2:
    	grantWrite();
    case 1:
    	grantRead();
}

위 코드는 로그인한 사용자의 등급(level)을 체크하여 등급에 맞는 권한을 부여하는 방식으로 되어 있습니다. 제일 높은 등급인 3을 가진 사용자는 읽기, 쓰기, 삭제 권한까지 모두 갖게 되고, 제일 낮은 등급인 1을 가진 사용자는 읽기 권한만 갖게 됩니다.

 

switch문의 제약조건

switch문의 조건식은 결과값이 반드시 정수여야 하며, 이 값과 일치하는 case문으로 이동하기 때문에 case문의 값 역시 정수여야 합니다. 그리고 같은 값의 case문이 여러 개이며, 어디로 이동해야할 지 알 수 없기 때문에 중복되지 않아야 합니다.

게다가 case문의 값은 반드시 상수여야 합니다. 변수나 실수, 문자열은 case문의 값으로 사용할 수 없습니다.

  • switch문의 조건식 결과는 정수 값(long타입 제외) 또는 참조형(객체 주소)만 허용
  • case문에는 정수 값, 문자열 리터럴 또는 참조형만 가능(중복 불가)
public static void main(String[] args) {
    int num = 10;
    final int ONE = 1;

    switch (result) {
        case '1':		// 가능 - 문자 리터럴
        case ONE:		// 가능 - 정수 상수
        case "YES":		// 가능 - 문자열 리터럴
        case Double d:		// 가능 - 참조형 (JDK 14부터)
        case num:		// 불가능 - 변수
        case 1.0:		// 불가능 - 실수
    }
}
JDK 14부터 switch문의 조건식에 참조형이 가능합니다. 다만 참조형의 경우 타입만 적으면 안되고 변수를 선언하듯이 'Double d'와 같은 형식으로 적어야 합니다.

 

 

그리고 case문은 다음과 같이 한 줄에 하나씩 쓰던, 한 줄에 붙여서 쓰던 상관없습니다.

switch (month) {
    case 1: case 2: case 3:
    	System.out.println("1분기");
    case 4:
    case 5:
    case 5:
    	System.out.println("2분기");
    default:
    	System.out.println("3, 4분기");
}

 

중첩 switch문

 

if문처럼 switch문도 중첩이 가능합니다. 

switch (gender) {
    case '1': case '3':
        switch (gender) {
            case '1':
            	//
            	break;
            case '3':
            	//
            	break;
            }
        break;
    case '2': case '4':
        switch (gender) {
            case '2':
            	//
                break;
            case '4':
            	//
                break;
            }
        break;
    default:
    	//
}

 

 

switch식

 

JDK 14부터 switch문의 기능이 확장되어서, 전통적으로 문장(statement)이었던 switch문이 식(expression)으로도 쓰일 수 있습니다.

cahr grade = switch (score/10) {
    case 9, 10 -> 'A';
    case 8 -> 'B';
    case 7 -> 'C';
    default -> {
        System.out.println("불합격");
        yield 'D';
    }
};
  • 콤마(,)로 여러 case를 합칠 수 있습니다.
  • break; 가 없어도 다음 case로 넘어가지 않습니다.
  • switch식 끝에 세미콜론(;)을 붙여야 합니다.
  • 여러 문장일 경우 괄호{ }로 묶고 yield 예약어로 값을 반환해야 합니다.
  • 반드시 모든 경우의 수를 다 처리해야 합니다.

 

switch 패턴 매칭

 

원래 switch문의 조건식에는 기본형과 String만 사용할 수 있었는데, 패턴 매칭(Pattern Matching) 기능이 도입되면서 JDK 21부터 다음과 같이 참조형도 가능하게 확장되었습니다. 패턴 매칭은 타입 검사(instanceof), 변수 바인딩, 그리고 값 분해(destructuring) 를 한 번에 수행할 수 있게 해주는 기능입니다.

double getArea(Shape s) {
    return switch(s) {
    	case null -> ...
        case Rectangle r -> ...
        case Triangle t -> ...
        case Circle c -> ...
        default -> ...
    }
}

switch 문을 사용할 때 2가지 주의사항이 있습니다.

  1. default case는 null을 처리하지 않기 때문에 NullPointerException을 방지하기 위해서는 null case를 추가해야 합니다.
  2. case는 첫 번째 것부터 내려가면서 순서대로 평가하기 때문에, 부모 클래스 타입이 자식 클래스 타입보다 먼저 위치하게 되면 자식 타입의 case는 절대 실행될 수 없습니다.

 

추가로 다음과 같이 null case와 default case를 같이 처리할 수도 있는데, 이때는 반드시 제일 마지막에 위치해야 하며, null이 왼쪽에 놓여야 합니다.

double getArea(Shape s) {
    return switch(s) {
        case Rectangle r -> ...
        case Triangle t -> ...
        case Circle c -> ...
        case null, default -> ...
    }
}

 

또한 case 안에 if문이 중첩된 경우에는 다음과 같이 case-when으로 더 간결하고 명확하게 작성할 수 있습니다.

 

 

 

반복문

 

반복문은 어떤 작업이 반복적으로 실행되게 할 때 사용되며, 반복문의 종류로는 for문과 while문, 그리고 while문의 변형인 do-while문이 있습니다. for문이나 while문에 속한 문장은 조건에 따라 한 번도 실행되지 않을 수 있지만 do-while문에 속한 문장은 무조건 최소한 한 번은 실행될 것이 보장됩니다.

 

그리고 for문과 while문은 구조와 기능이 유사하여 항상 서로 변환이 가능하기 때문에 반복문을 작성할 때 어느 쪽을 선택해도 좋으나, for문은 주로 반복 횟수를 알고 있을 때 사용합니다.

 

for문

 

for문은 반복 횟수를 알고 있을 때 적합합니다. for문은 아래와 같이 '초기화', '조건식', '증감식', '블럭{ }' 모두 4부분으로 이루어져 있으며, 조건식이 참인 동안 블럭{ } 내의 문장들을 반복하다 거짓이 되면 반복문을 벗어납니다.

for (초기화; 조건식; 증감식) {
    // 조건식이 참일 때 수행될 문장
}

 

초기화

반복문에 사용될 변수를 초기화하는 부분이며 처음에 한 번만 수행됩니다. 보통 변수 하나로 for문을 제어하지만, 둘 이상의 변수가 필요할 때는 아래와 같이 콤마(,)를 구분자로 변수를 초기화합니다.

for (int i = 0, j = 1; i <  10; i++) {...}

조건식

조건식의 값이 참(true)이면 반복을 계속하고, 거짓(false)이면 반복을 중단하고 for문을 벗어납니다. 조건문을 잘못 작성하면 블럭{ } 내의 문장이 한 번도 수행되지 않거나, 영원히 반복되는 무한 반복에 빠지기 쉬우므로 주의해야 합니다.

증감식

반복문을 제어하는 변수의 값을 증가 또는 감소시키는 식입니다. 매 반복마다 변수의 값이 증감식에 의해 점차 변하다가 결국 조건식이 거짓이 되어 for문을 벗어나게 됩니다. 

for (int i = 0; i < 10; i++) {...}	// 1씩 증가
for (int i = 10; i > 0; i--) {...}	// 1씩 감소
for (int i = 0; i < 10; i+=2) {...}	// 2씩 증가
for (int i = 0; i < 10; i*=3) {...}	// 3배씩 증가

 

또한 증감식도 쉼표(,)를 사용해 두 문장 이상을 하나로 연결해서 쓸 수 있습니다.

for (int i = 0, j = 10; i < 10; i++, j--) {...}

 

지금까지 살펴본 이 3가지 요소는 생략할 수 있으며, 심지어 모두 생략도 가능합니다.

for (;;) {...}

조건식이 생략된 경우, 참(true)으로 간주되어 무한 반복문이 됩니다. 대신 블럭{ } 안에 if문을 넣어서 특정 조건을 만족하면 for문을 빠져 나오게 해야 합니다.

 

그리고 다음과 같이 for문의 내부에 문장이 하나뿐인 경우 괄호를 생략할 수 있습니다.

for(int i = 0; i < 3; i++) 
    System.out.println("*");

 

중첩 for문

 

if문 안에 또 다른 if문을 넣을 수 있는 것처럼, for문 안에 또 다른 for문을 포함시키는 것도 가능합니다. 그리고 중첩의 횟수에는 거의 제한이 없습니다. 다음은 중첩 반복문을 사용한 구구단 예시입니다.

public static void main(String[] args) {
    for (int i = 2; i < 10; i++) {
        for (int j = 1; j < 10; j++) {
        	System.out.printf("%d x %d = %d%n", i, j, i*j);
        }
    }
}

 

향상된 for문

 

JDK 5부터 배열과 컬렉션에 저장된 요소에 접근할 때 기존보다 편리한 방법으로 처리할 수 있도록 for문의 새로운 문법이 추가되었습니다.

for (타입 변수명 : 배열 또는 컬렉션) {
    // 반복할 문장
}

향상된 for문은 조건식이 없어 편리하지만, 배열이나 컬렉션에 저장된 요소들을 읽어오는 용도로만 사용할 수 있다는 제약이 있습니다.

 

while문

 

while문은 if문처럼 조건식과 블럭{ }만으로 이루어져 있습니다. 다만 if문과 달리 while문은 조건식이 참(true)인 동안, 즉 조건식이 거짓이 될 때 까지 블럭{ } 내의 문장을 반복합니다.

while (조건식) {
    // 조건식의 결과가 참인 동안 수행될 문장
}

for문은 초기화, 조건식, 증감식을 한 곳에 모아 놓은 것일 뿐, while문과 동일합니다.

 

한 가지 주의할 점은 for문과 달리 while문의 조건식은 생략할 수 없다는 것입니다. 그래서 while문의 조건식이 항상 참이되는 무한 반복문을 작성하려면 true를 넣어야 합니다.

while (true) {
    ...
}

for 무한 반복문과 동일하게 블럭{ } 안에 if문을 넣어서 특정 조건을 만족하면 while문을 빠져나오도록 해야 합니다.

 

do-while문

 

do-while문은 while문의 변형으로 기본적인 구조는 while문과 같으나 조건식과 블럭{ }의 순서를 바꿔놓은 것입니다. 그래서 블럭{ }을 먼저 실행한 후에 조건식을 평가합니다. 

while문은 조건식의 결과에 따라 블럭{ }이 한 번도 실행되지 않을 수 있지만, do-while문은 최소한 한 번은 실행될 것을 보장합니다.

do {
    // 조건식의 결과가 참일 때 수행될 문장
} while (조건식);

그리 많이 쓰이지는 않지만, 반복적으로 사용자의 입력을 받아서 처리할 때 유용합니다.

 

break문

 

앞서 switch문에서 break문을 사용한 것처럼 반복문에서도 break문을 사용할 수 있습니다. break문은 자신이 포함된 가장 가까운 반복문을 벗어납니다. 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나게 합니다.

public static void main(String[] args) {
    int sum = 0;
    int i = 0;

    while (true) {
        if (sum > 100) break;
        ++i;
        sum += i;
    }

    System.out.println("i = " + i);		// i = 14
    System.out.println("sum = " + sum);		// sum = 105
}

 

continue문

 

continue문은 반복문 내에서만 사용될 수 있으며, 반복이 진생되는 도중에 continue문을 만나면 반복문의 끝으로 이동하여 다음 반복으로 넘어갑니다. for문의 경우 증감식으로 이동하며, while문과 do-while문의 경우 조건식으로 이동합니다.

continue문은 반복문 전체를 벗어나지 않고 다음 반복을 계속 수행한다는 점이 break문과 다릅니다. 주로 if문과 함께 사용되어 특정 조건을 만족하는 경우에 continue문 이후의 문장을 수행하지 않고 다음 반복으로 넘어가서 계속 진행합니다.

전체 반복 중에 특정 조건을 만족하는 경우를 제외할 때 유용합니다.

public static void main(String[] args) {
    for (int i = 0; i <= 10; i++) {
        if (i % 3 == 0) continue;
        System.out.println(i);		// 1, 2, 4, 5, 7, 8, 10
    }
}

 

이름 붙은 반복문

 

break문은 근접한 단 하나의 반복문만 벗어날 수 있기 때문에, 여러 개의 반복문이 중첩된 경우에는 break문으로 중첩 반복문을 완전히 벗어날 수 없습니다. 이때는 중첩 반복문 앞에 이름을 붙이고 break문과 continue문에 이름을 지정해 줌으로써 하나 이상의 반복문을 벗어나거나 반복을 건너뛸 수 있습니다.

public static void main(String[] args) {
    Loop1 : for(int i = 2; i <= 9; i++) {
        for(int j = 1; j <= 9; j++) {
            if (j == 5) break Loop1;
            System.out.println(i + "*" + j + "=" + i*j);
        }
        System.out.println();
    }
}

'Lang > Java' 카테고리의 다른 글

[Java 21] (6) - Object-oriented Programming 1  (0) 2025.09.29
[Java 21] (5) - array  (1) 2025.09.25
[Java 21] (3) - operator  (0) 2025.09.18
[Java 21] (2) - variable  (0) 2025.09.15
[Java 21] (1) - getting started with Java  (0) 2025.09.11