Chapter 4 조건문과 반복문

Jun-hee Cho·2023년 3월 23일
0

Java

목록 보기
5/13

1. 조건문 - if, switch

1.1 if문

if문은 가장 기본적인 조건문이며, 다음과 같이 '조건식'과 '괄호{}'로 이루어져 있다. 'if'의 뜻이 '만일 ~이라면...'이므로 '만일(if) 조건식이 참(true)이면 괄호{}안의 문장들을 수행하라.' 라는 의미로 이해하면 된다.

if (조건식) {
	// 조건식이 참(true)일 때 수행될 문장들을 적는다.
}

만일 다음과 같은 if문이 있을 때, 조건식 'score > 60'이 참(true)이면 괄호{}안의 문장이 수행되어 화면에 "합격입니다."라고 출력되고 거짓(false)이면, if문 다음의 문장으로 넘어간다.

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

위 if문의 조건식이 평가되는 과정을 단계별로 살펴보면 다음과 같다. 변수 score의 값을 80으로 가정하였다.

score > 60
->80 > 60
->true	// 조건식이 참(true)이므로 괄호{}안의 문장이 실행된다.

위 조건식의 결과는 'true'이므로 if문 괄호{}안의 문장이 실행된다. 만일 조건식의 결과가 'false'이면, 괄호{}안의 문장은 수행되지 않을 것이다.
블럭 내의 문장이 하나뿐인 경우 괄호{}를 생략할 수 있다.

조건식

조건식을 작성할 때 실수하기 쉬운 것이, 등가비교 연산자 '=='대신 대입 연산자'='를 사용하는 것이다. 예를 들어 'x가 0일 때 참'인 조건식은 'x==0'인데, 아래와 같이 실수로 'x=0'이라고 적는 경우가 있다.

if (x = 0) { ... } // x에 0이 저장되고, 결과는 0이 된다.
->if (0) { ... } // 결과가 true 또는 false가 아니므로 에러가 발생한다.

블럭{}
괄호{}를 이용해서 여러 문장을 하나의 단위로 묶을 수 있는데, 이것을 '블럭(block)'이라고 한다. 블럭은 '{'로 시작해서, '}'로 끝나는데, '}'다음에 문장의 끝을 의미하는 ';'을 붙이지 않는 다는 것에 주의하자.

블럭 내의 문장들은 탭(tab)으로 들여쓰기를 해서 블럭 안에 속한 문장이라는 것을 알기 쉽게 해주는 것이 좋다.

1.2 if-else문

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

if (조건식) {
	// 조건식이 참(0이 아닌 값)일 때 수행될 문장들을 적는다.
} else {
	// 조건식이 거짓(0)일 때 수행될 문장들을 적는다.
}

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

1.3 if-else if문

if-else문은 두 가지 경우 중 하나가 수행되는 구조인데, 처리해야할 경우의 수가 셋 이상인 경우, 한 문장에 여러 개의 조건식을 쓸 수 있는 'if-else if'문을 사용하면 된다.

if (조건식1) {
	// 조건식1의 연산결과가 참일 때 수행될 문장들을 적는다.
} else if (조건식2) {
	// 조건식2의 연산결과가 참일 때 수행될 문장들을 적는다.
} else if (조건식3) { // 여러 개의 else if를 사용할 수 있다.
	// 조건식3의 연산결과가 참일 때 수행될 문장들을 적는다.
} else { // 마지막에는 보통 else블럭으로 끝나며, else블럭은 생략가능하다.
	// 위의 어느 조건식도 만족하지 않을 때 수행될 문장들을 적는다.
}

첫 번째 조건식부터 순서대로 평가해서 결과가 참인 조건식을 만나면, 해당 블럭{}만 수행하고 'if-else if'문 전체를 벗어난다.
만일 결과가 참인 조건식이 하나도 없으면, 마지막에 있는 else블럭의 문장들이 수행된다. 그리고 else블럭은 생략이 가능하다. else블럭이 생략되었을 때는 if-else if문의 어떤 블럭도 수행되지 않을 수 있다.
예를 들어 다음과 같은 if-else if문이 있을 때, 변수 score값이 85라면, 다음의 과정으로 처리된다.

① 결과가 참인 조건식을 만날 때까지 첫 번째 조건식부터 순서대로 평가한다.(첫 번째 조건식은 거짓이므로, 두 번째 조건식으로 넘어간다.)
② 참인 조건식을 만나면, 해당 블럭{}의 문장들을 수행한다.
③ if-else if문 전체를 빠져나온다.

1.4 중첩 if문

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

위와 같이 내부의 if문은 외부의 if문보다 안쪽으로 들여쓰기를 해서 두 if문의 범위가 명확히 구분될 수 있도록 작성해야 한다.
중첩if문에서는 괄호{}의 생략에 더욱 조심해야한다. 바깥쪽의 if문과 안쪽의 if문이 서로 엉켜서 if문과 else블럭의 관계가 의도한 바와 다르게 형성될 수도 있기 때문이다.

1.5 switch문

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

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

다만 switch문은 제약조건이 있기 때문에, 경우의 수가 많아도 어쩔 수 없이 if문으로 작성해야 하는 경우가 있다.

switch문의 기본구조는 아래와 같다.

switch문은 조건식을 먼저 계산한 다음, 그 결과와 일치하는 case문으로 이동한다. 이동한 case문 아래에 있는 문장들을 수행하며, break문을 만나면 전체 switch문을 빠져나가게 된다.
① 조건식을 계산한다.
② 조건식의 결과와 일치하는 case문으로 이동한다.
③ 이후의 문장들을 수행한다.
④ break문이나 switch문의 끝을 만나면 switch문 전체를 빠져나간다.

만일 조건식의 결과와 일치하는 case문이 하나도 없는 경우에는 default문으로 이동한다. default문은 if문의 else블럭과 같은 역할을 한다고 보면 이해가 쉬울 것이다. default문의 위치는 어디라도 상관없으나 보통 마지막에 놓기 때문에 break문을 쓰지 않아도 된다.

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

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

switch (level) {
	case 3 :
    	grantDelete(); // 삭제권한을 준다.
    case 2 :
    	grantWrite(); // 쓰기권한을 준다.
    case 1 :
    	grantRead(); // 읽기권한을 준다.

switch문의 제약조건
switch문의 조건식은 결과값이 반드시 정수이어야 하며, 이 값과 일치하는 case문으로 이동하기 때문에 case문의 값 역시 정수이어야 한다. 그리고 중복되지 않아야 한다. 같은 값의 case문이 여러 개이면, 어디로 이동해야할 지 알 수 없기 때문이다.
게다가 case문의 값은 반드시 상수이어야 한다. 변수나 실수는 case문의 값으로 사용할 수 없다.

switch문의 제약조건
1. switch문의 조건식 결과는 정수 또는 문자열이어야 한다.
2. case문의 값은 정수 상수만 가능하며, 중복되지 않아야 한다.

switch문의 중첩
if문처럼 switch문도 중첩이 가능하다. 한 가지 주의할 점은 중첩 switch문에서는 break문을 빼먹기 쉽다는 것이다.

2. 반복문 - for, while, do-while

2.1 for문

for문은 반복 횟수를 알고 있을 때 적합하다. 구조가 조금 복잡하지만 직관적이라 오히려 이해하기 쉽다. 자세한 설명에 앞서 가장 기본적인 for문의 예를 하나 소개할까 한다.

for(int i = 1; i <= 5; i++) {
	System.out.println("I can do it.");
}

변수 i에 1을 저장한 다음, 매 반복마다 i의 값을 1씩 증가시킨다. 그러다가 i의 값이 5를 넘으면 조건식 'i <= 5'가 거짓이 되어 반복을 마치게 된다. i의 값이 1부터 5까지 1씩 증가하니까 모두 5번 반복한다. 만일 10번 반복하기를 원한다면, 5를 10으로 바구기만 하면된다. 이 한 가지 예만 알고 있어도 특정 작업을 원하는 만큼 반복할 수 있다. 그러나 for문은 이와 같은 단순 반복에 그치지 않고 다양하게 활용된다.

for문의 구조와 수행순서
for문은 아래와 같이 '초기화', '조건식', '증감식', '블럭{}', 모두 4부분으로 이루어져있으며, 조건식이 참인 동안 블럭{}내의 문장들을 반복하다 거짓이 되면 반복문을 벗어난다.

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

제일 먼저 '①초기화'가 수행되고, 그 이후부터는 조건식이 참인 동안 '②조건식 -> ③수행될 문장 -> ④증감식'의 순서로 계속 반복된다. 그러다가 조건식이 거짓이 되면, for문 전체를 빠져나가게 된다.

초기화
반복문에 사용될 변수를 초기화하는 부분이며 처음에 한 번만 수행된다. 보통 변수 하나로 for문을 제어하지만, 둘 이상의 변수가 필요할 때는 아래와 같이 콤마','를 구분자로 변수를 초기화하면 된다. 단, 두 변수의 타입은 같아야 한다.

for(int i = 1; i <= 10; i++) { ... } // 변수 i의 값을 1로 초기화 한다.
for(int i = 1, j = 0; i <= 10; i++ { ... } // int타입의 변수 i와 j를 선언하고 초기화

조건식
조건식의 값이 참이면, 반복을 계속하고, 거짓이면 반복을 중단하고 for문을 벗어난다. for의 뜻이 '~하는 동안'이므로 조건식이 '참인 동안' 반복을 계속한다고 생각하면 쉽다.

for(int i = 1; i <= 10; i++) { ... } // 'i <= 10'가 참인 동안 블럭{}안의 문장들을 반복

조건식을 잘못 작성하면 블럭{}내의 문장이 한 번도 수행되지 않거나 영원히 반복되는 무한반복에 빠지기 쉬우므로 주의해야 한다.

증감식
반복문을 제어하는 변수의 값을 증가 또는 감소시키는 식이다. 매 반복마다 변수의 값이 증감식에 의해서 점진적으로 변하다가 결국 조건식이 거짓이 되어 for문을 벗어나게 된다. 변수의 값을 1씩 증가시키는 연산자 '++'이 증감식에 주로 사용되지만, 다음과 같이 다양한 연산자들로 증감식을 작성할 수도 있다.

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

증감식도 쉼표','를 이용해서 두 문장 이상을 하나로 연결해서 쓸 수 있다.

for(int i = 1, j = 10; i <= 10; i++, j--) { ... } // i는 1부터 10까지 1씩 증가하고, j는 10부터 1까지 1씩 감소한다.

지금까지 살펴본 이 세 가지 요소는 필요하지 않으면 생략할 수 있으며, 심지어 모두 생략하는 것도 가능하다.

for(;;) { ... } // 초기화, 조건식, 증감식 모두 생략. 조건식은 참이 된다.

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

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

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

위의 문장에서 타입은 배열 또는 컬렉션의 요소의 타입이어야 한다. 배열 또는 컬렉션에 저장된 값이 매 반복마다 하나씩 순서대로 읽혀서 변수에 저장된다. 그리고 반복문의 괄호{}내에서는 이 변수를 사용해서 코드를 작성한다.

2.2 while문

for문에 비해 while문은 구조가 간단하다. if문처럼 조건식과 블럭{}만으로 이루어져 있다. 다만 if문과 달리 while문은 조건식이 '참인 동안', 즉 조건식이 거짓이 될 때까지 블럭{}내의 문장을 반복한다.

while문은 먼저 조건식을 평가해서 조건식이 거짓이면 문장 전체를 벗어나고, 참이면 블럭{}내의 문자을 수행하고 다시 조건식으로 돌아간다. 조건식이 거짓이 될 때까지 이 과정이 계속 반복된다.

① 조건식이 참이면 블럭{}안으로 들어가고, 거짓이면 while문을 벗어난다.
② 블럭{}의 문장을 수행하고 다시 조건식으로 돌아간다.

for문과 while문의 비교
1부터 10까지의 정수를 순서대로 출력하는 for문을 while문으로 변경하면 아래 오른쪽과 같다.

위의 두 코드는 완전히 동일하다. for문은 초기화, 조건식, 증감식을 한 곳에 모아 놓은 것일 뿐, while문과 다르지 않다. 그래서 for문과 while문은 항상 서로 변환이 가능하다. 그래도 이 경우 while문 보다 for문이 더 간결하고 알아보기 쉽다. 만일 초기화이나 증감식이 필요하지 않은 경우라면, while문이 더 적합할 것이다. 앞으로 소개할 예제들은 for문보다 while문이 더 적합하다고 판단된 것들이다.

while문의 조건식은 생략불가
한 가지 주의할 점은 for문과 달리 while문의 조건식은 생략할 수 없다는 것이다.

while() { // 에러. 조건식이 없음.
		...
}

그래서 while문의 조건식이 항상 참이 되도록 하려면 반드시 true를 넣어야 한다.

2.3 do-while문

do-while문은 while문의 변형으로 기본적인 while문과 같으나 조건식과 블럭{}의 순서를 바꿔놓은 것이다. 그래서 while문과 반대로 블럭{}을 먼저 수행한 후에 조건식을 평가한다. while문은 조건식의 결과에 따라 블럭{}이 한 번도 수행되지 않을 수 있지만, do-while문은 최소한 한번은 수행될 것을 보장한다.

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

2.4 break문

반복문에서도 break문을 사용할 수 있는데, switch문에서 그랬던 것처럼, break문은 자신이 포함된 가장 가까운 반복문을 벗어난다. 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나도록 한다.

2.5 continue문

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

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

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

2.6 이름 붙은 반복문

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

profile
최고가 되기 위해 최선을...

0개의 댓글