자바 6. 조건문 제어문 반복문

Bluewiz_YSH·2022년 7월 3일
0

이번 장에서는 자바에서 많이 쓰이는 실행문, 조건문에서 기본 중의 기본인 if 조건문과 switch case문 그리고 반복문에서 기본 중의 기본인 for문과 do while문 그리고 향상된 for문을 알아보겠다.

1. 조건문

(1) if 조건문

if 조건문이란 어떤 조건에 따라 값을 boolean 자료형으로 판단하여 그 값에 따라 아래 실행문을 수행하도록 처리한 코드문을 뜻한다.

형식은 다음과 같다:

if (조건 1) {

조건1이 참일 경우 실행문 //참이면 실행문 실행후 나머지 더이상 비교하지 않고 if문 밖으로 나감

}

else if(조건 2) {

조건2가 참일 경우 실행문 //참이면 실행문 실행후 나머지 더이상 비교하지 않고 if문 밖으로 나감

}

else if(조건 3) { //else if가 없을수도 있다. 그러면 if-else 구문으로
//조건에서 참이면 if문 실행문만 실행된 뒤 if 조건문 밖으로 나감
//조건에서 거짓이면 if문 실행문을 실행하지 않고 그냥 지나가 else 실행문을 실행한뒤 if 조건문 밖으로 나감

조건3이 참일 경우 실행문

}

.
.
.

else {

위의 모든 조건에서 거짓일 경우 마지막 실행문

}

일단 필자가 상황을 가정하여 직접 짠, if 코드문 예시를 보자.

어느 놀이공원이 방문한 고객들의 계층, 나이에 따라서 각각 다른 이용 요금을 알려주는 키오스크에 쓰일 프로그램을 만들고 싶어한다. 유치원생은 4000원, 초등학생은 5000원, 중학생은 6000원, 고등학생은 7000원, 나머지 성인은 8000원으로 가격을 맞추고 싶어하는데 이 때, 군인이나 임산부, 공무원, 국가유공자는 가격을 6000원으로 따로 책정해서 받고 싶어한다. 이 키오스크에 들어갈 데이터 서버 프로그램이 자바라고 가정할때 직접 코드를 작성해보시오.

class AmusementPricing {
		int price;
		String status;
		int age;

		if (status == "군인" || status == "임산부" || status == "공무원" || status == "국가유공자") // 바깥 전체 if문 군인 임산부 공무원 국가유공자 판별 ①
		{
			price = 6000;
			System.out.println("공공 할인 적용됨");
		} else // ①에서 거짓일시 (군인 임산부 공무원 국가유공자x) 들어가는 else문 ② (① + ② if-else 구문)
		{
			if (age <= 7) // (age < 8)도 가능②에서 나이가 7살 이하 유치원생 ③ if문
			{
				price = 4000;
				System.out.println("유치원생 할인 적용됨");
			} else if (age >= 8 && age <= 13) // (age <= 13) 혹은 (age < 14)도 가능 ②에서 나이가 8살 이상 12살 이하 초등학생 ④ else if문
			{
				price = 5000; 
				System.out.println("초등학생 할인 적용됨");
			} else if (age >= 14 && age <= 16) // (age <= 16) 혹은 (age < 17)도 가능 ②에서 나이가 13살 이상 16살 이하 중학생 ⑤ else if문
			{
				price = 6000;
				System.out.println("중학생 할인 적용됨");
			} else if (age >= 17 & age <= 19) // (age <= 19) 혹은 (age < 20)도 가능 ②에서 나이가 17살 이상 19살 이하 고등학생 ⑥ else if문
			{
				price = 7000;
				System.out.println("고등학생 할인 적용됨");
			} else // ②에서 19살 초과 성인 else 구문 ⑦ ( ③ + ④ + ⑤ + ⑥ + ⑦ if-else 구문, 그리고 이 구문 전체를 ② else 구문이 감싸고 있다)
			{
				price = 8000;
				System.out.println("할인 적용 안됨, 성인 요금");
			}
		}
		System.out.println("고객님이 내셔야할 요금은 " + price + "원 입니다." );
        //if 조건문이 끝나면 요금 출력
}

상황에 맞춰 필자는 먼저 이용 요금을 price, 사람에 따른 계층을 status, 나이를 age로 멤버 변수 변환해놓고 코드 입력을 시작하였다. 여기서 if 조건문을 쓰되, 일단 처음에는 이 사람이 군인인지 임산부인지 공무원인지 국가유공자인지 확인하고 (버티컬 바 || 사용해 논리합 또는 OR 조건 표시, ①) 맞다면 콘솔에 "공공 할인 적용됨"이 출력되고 price는 6000으로 대입된 상태에서 if문을 나와 제일 맨 마지막 줄, "고객님이 내셔야할 요금은 6000(price)원 입니다."로 나올것이다.

그런데 군인 임산부 공무원 국가유공자 모두 다 아니라면 (① 조건에서 거짓) ②에 들어가 또 안에 있는 ③ + ④ + ⑤ + ⑥ + ⑦ if-else if-else 구문을 차례로 돌면서 age 나이가 몇이 되는지에 따라 콘솔에 출력되는 할인 사항과 요금이 달라진다.(유치원생-초등학생-중학생-고등학생-성인)

즉, true 참이 나오는 조건을 찾으면 그 참 조건문의 실행문만 실행하고 다른 조건은 더이상 비교하지 않고 if 조건문 밖으로 나온다.

(물론 age값을 15으로 두고 조건문 코드를 실행하면 중학생 조건에 대해 (age >= 14 && age <= 16)로 표현해도 작동에는 무리가 없지만 걸치는 자리인 (age <= 16) 또는 (age < 17)로 표현해도 된다.

왜냐면 if 조건문 유형은 위에서 아래로 순차적으로 비교하면서 앞의 초등학생 else if문에서 (age >= 8 && age <= 13) 혹은 (age <= 13) 혹은 (age < 14)을 이미 비교했기때문에 이 부분이 먼저 false로 처리되서 중학생 조건으로 빠지기 때문이다. 나머지 유치원생 고등학생 성인 조건도 마찬가지이다. 오히려 (age < x)로 쓰는 편이 코드가 더 깔끔하다.)

전체적인 구조는 그래서 ① + ② if-else 구문이지만 ②안에는 ③ + ④ + ⑤ + ⑥ + ⑦ if-else if-else 구문으로 또 나뉘어지는것이다.이를 if-else 조건문 안에 또 if-else if-else문이 있다고 해서 중첩된 if 조건문이라고 한다.

이렇게 조건문 소스 코드를 만든 뒤 status와 age를 달리 조절해서 실행해보면 위 사진들 같이 조건문에 잘 작동하는 모습을 볼 수 있다.

그런데 만약, 아래 코드처럼 나이 조건문들을 else-if가 아닌 if 조건문으로 바꾸면 어떻게 될까?

		int price;
		String status = "";
		int age = 7;

		if (status == "군인" || status == "임산부" || status == "공무원" || status == "국가유공자")
		{
			price = 5000;
			System.out.println("공공 할인 적용됨");
		} else
		{
			if (age < 8)
			{
				price = 4000;
				System.out.println("유치원생 할인 적용됨");
			} if (age < 14)
			{
				price = 5000;
				System.out.println("초등학생 할인 적용됨");
			} if (age < 17)
			{
				price = 6000;
				System.out.println("중학생 할인 적용됨");
			} if (age < 20)
			{
				price = 7000;
				System.out.println("고등학생 할인 적용됨");
			} else
			{
				price = 8000;
				System.out.println("할인 적용 안됨, 성인 요금");
			}
		}
		System.out.println("고객님이 내셔야할 요금은 " + price + "입니다." );

결과는 위 사진처럼 나오는데, 왜냐면 else if가 아닌 그냥 if 조건문으로 하면 첫번째 조건 결과가 참으로 나와서 실행문을 실행해도 if 조건문 밖으로 나오는게 아니라 else if나 else 조건문을 만나기 전까지 나머지 조건 전부를 돌려서 참인 조건문에 대해서만 전부 위에서 아래로 순차적으로 실행한다.

그래서 age 값이 7일때 age < 8, age < 14, age < 17, age < 20에 대해 모두 참이므로 각각 해당 조건문에 해당하는 실행문을 순차적으로 실행한 뒤 (유치원생, 초등학생, 중학생, 고등학생 할인 적용됨) 마지막 else는 거짓일때만 실행되기에 실행되지않고 if문을 나와서 마지막 출력문, "고객님이 내셔야할 요금은 7000원 (<= 마지막 참 실행 age < 20일때 price가 7000으로 대입되었으므로) 입니다."가 나온것이다.

이처럼 if-else if-else 조건문이 쓰이는 용도는 하나의 상황에 여러 조건들을 비교하고 그것에 딱 맞는 조건만을 찾아서 그에 해당하는 유일한 결과값을 도출해내고 싶을때 쓰이고 else if가 없는 if 조건문은 여러 조건이 아닌, 단일 개별 조건에 대해서만 쓰인다.

+) if 단일 조건문에 대해서 우리가 앞서 배웠던 삼항 연산자를 사용할수 있다.

int a = 1;
String result1, result2; //String 자료형, 기본 자료형과는 다르며 이름은 문자열, 주로 다수의 문자로 이뤄진 문장이나 한 글자 문자를 문자열로 변수값을 저장할때 쓰는 자료형이라고 보면 된다. 문장, 문자열을 변수에 대입할때 꼭 오른쪽 항 문자를 "" 큰따옴표 double quatation으로 꼭 감싸줘야한다.

if(a < 0) {
result1 = "0보다 작다.";
System.out.println(result1);
}
else {
result2 = "0과 같거나 0보다 크다";
System.out.println(result2);
}
int a = 1;

String rst = (a < 0) ? "0보다 작다" : "0과 같거나 0보다 크다"; //실행문 결과값이 담길 변수 = (조건식) ? 참일때 결과값 : 거짓일때 결과값;

System.out.println(rst);

그럼 아래 사진처럼 if 조건문으로 적은 것과 삼항 연산자로 적은 것 둘 다 같은 결과 값이 나온다. 다만, 코드는 한 줄 안에 다 쓸수 있기에 매우 간편하다.

(2) switch-case 조건문

switch-case 조건문이란 if 조건문에서 조건이 항이 많은 복잡한 조건식이 아니라 조건값이 단순히 숫자거나 문자(열)일때 if-else if-else 조건문을 일일이 적는것보다 간단히 그리고 가독성 좋게 적을수 있는 조건문 유형으로 형식은 아래과 같다:

switch(조건(값) == int 이하 자료형 값, 문자(열)) {

case 조건값1 : 실행문;

break; // 조건값1 해당할시에 (나머지 더 이상 비교하지 않고) switch 조건문 밖으로 나감

case 조건값2 : 실행문;

break; // 조건값2 해당할시에 (나머지 더 이상 비교하지 않고) switch 조건문 밖으로 나감

//중첩된 for 반복문에서 보겠지만 break문은 조건이 참으로 만족하면
//자기를 감싸고 있는 가장 가까운 반복문의 밖으로 빠져나감
//그래서 break;만 기술하면 가장 밖 전체를 감싸는 for문은 못 빠져나감

.
.
.

default : 실행문; (생략가능) //주어진 값에서 모든 조건에 비교했을때 모두 거짓일 경우 마지막 실행되는 실행문

}

그럼 내가 실습했던 예시를 아래 코드에서 보자.

int chk = 0;
String area = "서울시";
String area_number;

switch(area) {
case "서울시" : area_number = "02"; break;
case "과천시" : case "고양시" : case "안산시" : case "안양시" : area_number = "031"; break;
case "인천시" : area_number = "032"; break;
case "진주시" : case "통영시" : case "사천시" : case "김해시" : case "양산시" : area_number = "055"; break;
default : chk = 1; area_number = "찾으시는 국번이 확인되지 않습니다.";
}
        
if(chk == 0) System.out.println(area + "의 국번은 " + area_number + "번 입니다.");
else System.out.println(area_number);

일단 겉보기에 switch-case 구문과 if 구문이 동시에 쓰였다는것을 알 수 있다. 그리고 조건(값)이 아주 많지만 몇몇 조건값이 참일 경우 실행되는 실행문이 서로 일치할 경우 저렇게 case 조건1(값): case 조건2(값): case 조건3(값): ... case 조건n(값):으로 퉁쳐서 한 줄안에 묶고 실행문은 하나만 적어도 된다.

분석하자면 일단 switch-case 구문에서 조건(값)으로 쓰이는건 String 문자열 자료형의 area 변수고 area 변수가 어떤 값이냐에 따라 case 옆에 값을 적어주면서 각각의 조건들을 기술하고 있으며 그에 따른 실행은 String 문자열 자료형의 area_number 값이 각각 따로 따로 대입되는것을 알 수 있다.

거기다 만약 area 변수 값이 switch-case 구문에서 기술해놓은 모든 조건값과 일치하지 않을 경우 실행되는 실행문을 default에서 기술하고 있는데 int 자료형 chk값이 1로 변하고, area_number가 "찾으시는 국번이 확인되지 않습니다."로 변경되는것이 바로 그것이다.

그렇게 마지막에 switch-case 구문을 나오면서 chk값이 처음 0을 계속 유지하느냐 아니면 1로 변하냐에 따라 하단 if문과 연관되어 마지막 콘솔 출력문 값이 달라지는것까지 되는것이 본 예시의 자세한 구조이다.

이 상태에서 실행을 한다면 아래 사진과 같이 "서울시" 조건에 해당해 area_number가 02번이 되고 chk값은 여전히 0으로 나와 if문에서 조건 참에 해당해 서울시의 국번이 제대로 출력됨을 알수 있다.

여기서 area를 "하남시"로 바꾼다면 어떻게 될까? 그 결과는 아래 사진과 같다.

"하남시"는 case 조건(값) 어디에도 없었기에 default 실행문이 실행되고 chk 값이 1으로 변경됨과 동시에 area_number도 "찾으시는 국번이 확인되지 않습니다."으로 바뀌면서 마지막 if문에서 거짓에 해당되기에 else문 실행문인 area_number값을 콘솔에 출력하는 결과로 나오게 된것이다.

if문과 switch-case 구문과 구별되는 점은 break문의 유무인데 만약 break문이 없다면 어떻게 될까?

아래처럼 break문만 빼본채 switch-case 구문을 작성해 실행을 해보았다.

		String s = "C";
		String str;
		switch (s)
		{
		case "A":
			str = "1";
			System.out.println(str);
		case "B":
			str = "2";
			System.out.println(str);
		case "C":
			str = "3";
			System.out.println(str);
		case "D":
			str = "4";
			System.out.println(str);
		case "E":
			str = "5";
			System.out.println(str);
		default:
			str = "6";
			System.out.println(str);

그럼 아래 사진처럼 결과값이 나온것을 볼 수 있는데 이건 왜 이런거냐면, 해당 조건값 "C"가 case "C"와 만나 참이 되면서 str값이 3이 되고 이걸 콘솔에 출력하고 break문이 있던 전처럼 switch-case문을 나가는게 아니라 switch-case문을 default 끝까지 돌면서 참이 된 조건값의 실행문부터 default 실행문까지 전부 참으로 실행해버리기 때문에 이런 값이 나온것이다.

그래서 switch-case문에서는 break문을 빼먹지 말고 쓰는것이 굉장히 중요하다.

2. 제어문 반복문

(1) for문

반복문은 제어문이라고도 불리며 특정 식을 여러번 반복 수행하는 코드문이라고 생각하면 된다. 자바에서 정말 많이 쓰이는 코드식이라고 할수 있다. 그 중 가장 기본이 되는게 for문이다.

for문의 형식은 다음과 같다:

for(초기식; 조건식; 증감연산자 //후위연산자) {

실행문; (조건문, 반복문, 출력문, 지역변수...)

//지역변수는 메소드 아래에서 처음 선언 & 초기화된 변수를 뜻한다

}

여기서 초기식은 맨 처음 딱 한번만 실행되는 식으로 int i = 0;를 많이 쓴다. 보통 반복의 순서 주기인 i를 가지고 선언 및 초기화하는 부분이 여기다.

조건식은 초기식과 뒤에 나올 증감연산자로 인해 i가 증감하는데 이때 여기서 i가 얼마나 증감해야하는지 정해둘수 있다. 즉, 특정 i 값 수준을 정해놓고 (반복 주기 제한) 그 조건이 만족하지 않을때까지 반복문을 실행되도록 만드는, 반복문의 목표 반복 주기를 정하는 조건식이라고 보면 된다. true false 값 반환을 반환하며 보통 i<변수.length 형식으로 쓰인다. 만약 i가 해당 조건식보다 더 크거나 작다면 조건식에 맞지 않으므로 for문을 나가서 반복 기준인 변수 i 자체가 없어진다.

증감식은 후위연산자를 이용해 반복문 안 실행문이 한번 다 실행되고나서 반복 주기인 i의 카운트를 1 올려주거나 내려준다 보통 i++를 많이 쓴다.

예시를 한번 보자.

System.out.println("for문 1");
for (n = 1; n <= 10; n++) {
	System.out.println("Hello Java" + n);
}
	System.out.println("n의 값은: " + n);
	System.out.println("for문을 빠져 나옴.");
    System.out.println("n의 값은: " + n);
	System.out.println("for문을 빠져 나옴.");
	System.out.println("\n==============\n");

아래 사진처럼 Hello Java + n(Hello Java 10번 반복 + n은 1부터 10까지 계속 증가)를 계속 출력하는걸 반복했음을 알 수 있다. 또한, 안에 반복 주기를 표현하는 n은 미리 정해둔 반복 횟수(n <= 10;)이 완료된후 후위연산자 n++ 때문에 10이 아닌 11이 되었음을 알수 있다. "for문을 빠져 나옴."문장 또한 마찬가지로 for 반복문이 정해둔 반복 횟수만 반복하고 빠져나옴을 알려주는 문구이다.

여기서 더 나아가 for문은 상황에 따라 코드가 중복되거나 논리 흐름상 필요가 없을때 해당 for문에서 초기식/조건식/증감연산자를 생략할수도 있다.

//초기식 생략: for문 바깥의 이미 다른곳에서 선언 및 초기화

int i = 0;

for( ; i < 5; i++) {
...
}

//조건식 생략: 조건식을 바로 정할수는 없고 어떤 연산 결과 값이 나왔을때 맞춰 
//for문을 중단시켜야 한다면 조건식을 생략하고 for문 실행문 부분 안에서 if문 사용해
//조건식이 없고 if문이 그 조건식 역할을 대신하는 for문을 적을수 있다

for(int i = 0; ;i++) {
sum += 1;
if(sum > 200) break;
}

//증감식 생략: 증감식이 복잡하거나 다른 변수의 연산 결과값에 좌우된다면 생략하고 for문 실행문 안에 대신 쓸수 있다

for(int i = 0; i < 5; ) {
...
i = (++i) % 10;
...
}

//요소 모두 생략: 무한 반복하는 경우에 사용 가능

for( ; ; ) {
...
}

for문을 더 응용하면 중첩된 for 반복문도 쓸수 있다.

중첩된 for 반복문이란 우리가 앞서 if 조건문에서도 중첩된 if 조건문을 보았는데 이와 비슷하게 중첩된 for문도 바깥 for문 안에 for문이 또 있는 코드문을 가리킨다. 대표적으로 예제는 구구단을 출력하는게 잘 알려져있다.

for (int i = 1; i <= 9; i++) {
System.out.println("구구단" + i + "단\n"); //"\n"은 System.out.println();과 마찬가지로 한줄 띄기 역할을 한다. enter 기능
for (int j = 1; j <= 9; j++){
System.out.println(i + "x" + j + " = " + i * j);
}
System.out.println();
}

이렇게 아래 사진처럼 구구단의 모습이 나오는데 겉만 보면 중첩된 for문에서 바깥 for문(i)은 맨 처음 "구구단 1단, 2단, 3단 ... 9단"의 문장을 반복 출력하는데 작용하면서

중요하게는 안쪽 for문(j)에서 구구단의 실질적인 계산값인 i * j의 i부분을 담당하고 있기 때문에 그렇다.

그리고 안쪽 for문(j)는 i * j의 j부분을 담당하고 있다.

이런 상태에서 반복 주기에 따라 상세히 보면
i가 1일때 j는 1,2,3,4...9까지 반복문을 계속 돌려서 i가 1인 상태에서 j가 10 이상이 될때까지 for문을 돌린다. (구구단 1단 완성)

그렇게 j가 10이 되면 안쪽 for문을 나와 바깥쪽 for문이 실행되면서 i는 1에서 2가 되고 다시 안쪽 for문이 j는 1부터 실행되는것이다.(구구단 2단 시작)

그렇게 i와 j 둘 다 9단까지 처리되도록 i와 j 조건식 모두 9보다 같거나 작게로 잡혀져있으며 i와 j 모두 10 이상이 되면 더이상 for문은 실행되지 않는다.

이렇게 중첩된 for문에서는 반복의 주기 횟수를 표시하는 초기식의 변수가 2개 이상이고 가장 바깥쪽 for문은 안쪽 for문이 더이상 조건식에 참이 되지 않을 정도로 반복문이 실행된 뒤에서야 반복 주기 횟수가 한번 증가하는것이다.

덧붙여 여기서 반복문이라면 중요하게 짚고 넘어가야할 break문과 continue문에 대해 알아보겠다.

break문은 우리가 앞서 switch-case문에서 보았듯이 switch-case 조건문에서 해당 조건이 참이면 그 조건문의 실행문을 실행한 뒤 더이상 다른 조건문을 보지않고 switch-case 조건문 밖으로 나갔었다.

반복문에서도 이 break문이 조건에 맞으면 해당 코드문 밖으로 나가는건 동일하다. 다만, 반복문에서의 break문은 실행문안에서 반복을 끝내는 조건과 바로 밑 break문을 써놓음으로써 걸어둔 반복문이 일정 주기로 반복을 실행하다가 특정 반복 순간에 그 조건에 맞춰 참이 되면

밑에 있는 break문이 실행되어 더이상 반복을 실행하지 않고 break문을 처음 감쌌던, 최초의 반복문 밖으로 나가게 된다.

(그래서 break;문 만으로는 나중에 기술할 중첩된 for문에서 안쪽 for문만 바깥으로 나가지 가장 바깥 for문의 아예 for문 밖으로 나가지는 못한다. 가장 바깥의 for문을 나가기 위해선 다른 방법이 있는데 그 부분은 나중에 따로 덧붙여 기술한다.)

break문의 유무 차이를 쉽게 알수 있는 예제를 한번 보자.

int sum = 0;
int num = 0;

for(num = 0; sum < 100; num++) {
sum += num;
}

System.out.println("num : " + num);
System.out.println("sum : " + sum);

위의 예제는 보다시피 0부터 시작해 1씩 올려지는 num을 다 더해 그 총합을 sum이라 할때, sum이 100을 넘어가는 순간에 해당하는 num값과 sum값을 콘솔에 출력하고자 만든 코드문임을 알 수 있다.

그런데 이대로 실행해보면 아래 사진처럼 나온다.

sum은 105가 넘는 수로 나오며 원하는 결과를 얻었지만 문제는 num인데, 사실 num이 15가 아닌 14일때 sum이 105가 넘게 되므로 num은 예제의 본래 의도에서 바라는 결과가 아니다.

바로 이때 쓸수 있는게 break문이다. 정확히는 for문 실행문 안에다가 num이 15가 되기전 (num이 14일때) sum이 100을 넘는 결과값을 가지는, 정확한 순간을 가리키는 if 조건식과 그 아래 그때 반복문을 바로 나갈수 있도록 break문을 넣어 원하는 결과값을 도출해낼수 있다.

그런 점을 반영해 수정한 코드문은 아래와 같다.

int sum = 0;
int num = 0;

for(num = 0; ; num++) {
sum += num;
if(sum >= 100)
break;
}

System.out.println("num : " + num);
System.out.println("sum : " + sum);

바뀐 점은 항상 있던 for문 ()에 조건식이 생략되었고 이를 대신하는 if조건문과 break문이 for문 실행문 안쪽에 sum += num 바로 아래 위치하고 있으며 그래서 num이 14일때 sum 작업을 통해 sum이 105가 되자마자 바로 if문 조건에 따라 참이 발동, 그 아래 실행문인 break가 발동해 그 즉시 for문을 나간다. 이는 전에 코드문에서는 sum이 105여도 for문을 바로 나가지 않아 m이 14에서 멈추는게 아니라 후위 연산자 num++로 인해 15로 올라가는것과 상반되는 결과를 낳는 셈이다.

다음은 continue문이다.

continue문은 특정 조건이 참이면 반복문을 실행하지 않고 건너뛴다고 생각하면 편한데, 정확히는 해당 주기 반복을 실행하지 않고 건너뛰면서 continue문을 직접 감싸고 있는, 해당 최초 반복문으로 다시 돌아가 후위연산저 처리후 그 다음 주기부터 다시 반복하게 하는 코드문이다.

아래 예제를 보자.

int total = 0;
int num;

for(num = 1; num <= 100; num++) {
if(num % 2 == 0)
continue;
total += num;
}
System.out.println("1부터 100까지의 홀수의 합은 " + total + "입니다. ");

아래 사진처럼 나오는데 1부터 100까지 정확히 홀수만 골라내도록 작용한 부분은 바로 if(num % 2 == 0)의 if조건문과 continue문이다.

num은 반복문을 거치면서 후위연산자때문에 1씩 증가하는데 이 num이 2로 나뉜 나머지 (num % 2)가 만약 0이라면은 이건 짝수를 가리키므로 if 조건문이 참이 되고

그러면 바로 아래 실행문인 continue문이 실행되면서 해당 짝수에 해당하는 반복 주기는 건너뛰기가 된다. 그래서 num이 짝수일때 total에 num이 더해지는 식 total += num이 실행되지 않고 다시 위로 올라가 후위연산자 num++가 작용하여 짝수에서 홀수가 된 상태에서 반복문이 다시 실행되는것이다.

이때는 num이 홀수이므로 if 조건문에서 거짓이 되니 continue문 또한 실행되지 않으며 그대로 total += num이 실행돼 홀수가 total에 더해지는 결과를 낳는다.

결국 num이 100을 초과하는 순간까지 total += num은 실행되어 1부터 100까지 홀수만 더한 합이 완성되어 콘솔에 출력되는것이다.

이를 살짝 응용해 if 조건문 num % 2 == 0에서 num % 2 != 0 (num이 2로 나뉜 나머지가 0과 같지 않다는 의미 즉, 홀수를 가리킴)으로 바꾸면

1부터 100까지 '짝수'만 더한 합이 나올수 있을것이다.

이처럼, break문과 continue문은 제어문 반복문에서 어떤 조건에 맞춰 반복문의 진행방향을 바꿀수 있는 분기처리문이라고 불리기도 하며 주로 if조건문과 함께 반복문 실행문 안쪽에 위치한다. 또한 break문은 switch-case문과 반복문, continue문은 반복문 (for 반복문은 물론 뒤에서 배울 while, do-while 반복문) 안에서만 쓰일수 있다.

자 그런데 여기서 중첩된 for문과 break문 혹은 continue문이 만날 경우, 결과는 어떻게 달라질까?

아래 예제들을 한번 보자.

중첩된 for문 + break문 (라벨x)

	for (int i = 2; i <= 9; i++)
		{
			if (i < 4)
				System.out.println("구구단 " + i + "단"); 
                //조건식 실행문이 하나인 경우에는 중괄호 표시 x
			for (int j = 1; j <= 9; j++)
			{
				if (i == 4)
					break;
				System.out.println(i + "*" + j + "=" + (i * j));
			}
			System.out.println();
		}
		System.out.println("\n==============\n");

해당 코드문은 break문을 써서 9단의 구구단 중 1단부터 3단까지만 출력하고 싶어서 코드를 작성했다.

그리고 결과는 아래 사진과 같았다.

원하는 결과는 3단까지만 이었는데 4단은 건너뛰고 구구단이 몇단인지 표시도 없이 5단, 6단...9단까지 그대로 출력되었다. 왜 이런일이 벌어진걸까? 그것은 바로 우리가 앞서 break문과 continue문에서 언급했던, 해당 코드문을 감싸고 있는, 최초의 반복문 밖까지만 break문이 작동하기 때문이다.

그래서 중첩된 for문에서는 break;만 입력해둔 채로 실행하면 해당 break 조건이 참일때
가장 안쪽 반복문에 대해서만 반복문 탈출이 적용되고 바깥 반복문은 적용이 안되는것이다.

이를 해결하기 위해선 가장 바깥 for문에 라벨을 붙이고 break 조건이 참일때 가장 바깥 for문으로 탈출하도록 break문 다음에 라벨을 직접 언급해야한다. 바로 아래처럼 말이다.

중첩된 for문 + break문 (라벨O)

		gugudan: for (int i = 2; i <= 9; i++) // for문 바로 위 라벨 표시
		{
			if (i < 4)
				System.out.println("구구단 " + i + "단");
			for (int j = 1; j <= 9; j++)
			{
				if (i == 4)
					break gugudan; // break + 라벨명 => 최초의 for문이 아닌 지정 라벨의 for문 바깥으로 빠져나감
				System.out.println(i + "*" + j + "=" + (i * j));
			}
			System.out.println();
		}
		System.out.println("\n==============\n");

이러면 아래 사진처럼 2단 3단만 나오는, 원하던 결과가 잘 나온다.

continue도 마찬가지이다. 라벨을 안 붙이고 단순히 짝수단만 출력하려고 했을때 코드는 다음과 같고 아래 사진과 같이 원하던 결과가 나오지 않는다.

중첩된 for문 + continue문 (라벨x)

		for (int i = 2; i <= 9; i++)
		{
			if (i % 2 == 0)
				System.out.println("구구단 " + i + "단");
			
			for (int j = 1; j <= 9; j++)
			{
				if (i % 2 == 0)
					System.out.println(i + "*" + j + "=" + (i * j));
				else
					continue;
			}
			if(i % 2 != 0) //홀수단 조건
				System.out.println("구구단 " + i + "단 표시 안됐어!");
			System.out.println();

짝수단만 출력하고 홀수단 내용은 아예 없애버리고 싶기에 바깥 for문에 위의 break의 경우와 똑같이 gugudan 라벨을 붙이고 continue문에도 직접 gugudan 라벨을 입력해서 수정했다.

gugudan: for (int i = 2; i <= 9; i++) // for문 바로 위 라벨 표시
		{
			if (i % 2 == 0)
				System.out.println("구구단 " + i + "단");
			
			for (int j = 1; j <= 9; j++)
			{
				if (i % 2 == 0)
					System.out.println(i + "*" + j + "=" + (i * j));
				else
					continue gugudan; // continue + 라벨명 => 최초의 for문에서 해당 차수를 건너뛰고 다시 반복하는게 최초 for문이 아닌 지정 라벨의 for문으로 다시 반복함
			}
			if(i % 2 != 0)
				System.out.println("구구단 " + i + "단 표시 안됐어!");
			System.out.println();
		}
		System.out.println("\n==============\n");

그랬더니 아래 사진과 같이 원하던 결과가 나왔다.

즉, break문과 continue문을 이용해서 분기처리를 해주는것도 중요하지만 항상 그 분기때마다 break문과 continue문이 어디까지 작용하는지 확실히 알아두고

중첩 for문이나 조건문 등 여러 조건문 제어문 반복문이 얽혀서 있는 경우 원하는 결과값을 위해 어디로 분기처리의 끝이 흘러야 하는지 파악한 다음 필요하다면 그 지점을 특정 라벨로 지정해 break문 혹은 continue문에 직접 언급을 해줘야 한다는 사실을 잊지 말아야 한다.

(2) while문 + do-while문

먼저 while문은 조건식이 참인 상황 동안 (while) 실행문 안 분기처리문이 따로 없다면 계속 반복되는 반복문이다. 그래서 웬만하면 분기처리문 입력은 필수이다. 형식은 다음과 같다:

while(조건식 또는 값) {

실행문; (분기문 break or continue과 조건식을 만족시킬수 있는 증감식 둘 중 하나는 필수, 출력문/지역변수/제어문/조건문)

}

그럼 간단한 예제를 해보고 실행해보자.

int total = 0;
int i = 1;

while(i <= 10) {
	total += i;
	i++;
}
    
System.out.println("1부터 10까지 더한 총합: " + total);
System.out.println("while문을 나오고 난 뒤의 i값: " + i);
System.out.println("\n==============\n");

그러면 아래 사진과 같이 while의 조건인 i가 10이하일때까지 1부터 10까지 차례로 더한 값 (total)과 while문을 i가 더이상 10 이하가 아니게 될때까지 수행한 다음 마지막에 while문을 나오게 되고 11로 바뀐 i값이 마지막에 콘솔에 출력되는 모습까지 나오는걸 볼 수 있다.

이처럼 while문은 주어진 조건식이 참인 동안 계속해서 반복이 되므로 일부의 경우에서는 이 조건식이 항상 참이 되는 상황을 일부러 만들어 쓰기도 한다. 즉 while문 안에 있는 실행문이 무한 반복이 된다는 뜻이다.

이런 경우에는 보통 항상 켜져 있어야 하는 웹서버가 해당이 되며 단순히 보자면 무한 반복되는 while문 코드 패턴은 아래와 같다:

while(true) {
...
}

그 다음은 do-while문이다. while문은 주어진 변수와 관련된 조건식이 엮이면서 서로 참이지 않으면 한번도 실행이 되지 않는데 do-while문은 반면 조건식이 참이든 거짓이든 상관없이 일단 처음 한번 실행된 뒤에 이후에도 실행문을 반복할건지 조건문을 마지막에 보는 반복문이다.
형식은 다음과 같다:

do {
실행문; (분기문 break or continue과 조건식을 만족시킬수 있는 증감식 둘 중 하나는 필수, 출력문/지역변수/제어문/조건문)

} while (조건식 또는 값);

do로 인해 먼저 꼭 한번은 실행됨, 나머지는 while 조건문과 같음.

한번 아래 예제를 해보고 실행해보자.

int i = 5;
do {
	System.out.println(i + " ");
	i--;
} while(i>=1);
System.out.println("\ndo~while문 종료 후 : " + i + "\n");
System.out.println("\n==============\n");

그러면 아래와 같이 처음 5였던 i가 5부터 하나씩 줄면서 한줄씩 따로 따로 출력되는 반복 수행을 거쳐 i가 더이상 1보다 크지 않을때 do-while문을 빠져나오면서 아래 마지막 i값이 담긴 출력문까지 수행하면서 프로그램이 종료하게 된다.

이렇게 우리는 이번장에서 if 조건문부터 switch-case 조건문 그리고 반복문인 for문, 중첩된 for문, 반복문과 같이 쓰이는 break문과 continue문 그리고 마지막 반복문 유형인 while문과 do-while문까지 전부 둘러보았다.

그러면서 아마 어떤 조건문들을 어떤 상황에 써야할지 눈치챘을텐데, 먼저 else문이나 else if문이 없는 단순 if문은 개별 단일 조건만 있을때 써야하고 if-else if-else문은 하나의 상황에 대해 여러 조건들을 비교해 딱 맞는 조건에 대해서만 값을 도출할때 써야하며,

while문도 for문도 둘 다 반복 횟수가 명확히 정해져 있을때나 if문이나 break, continue문과 결합하여 조건식의 참, 거짓에 따라 반복 실행을 달리 줘야하는 때도 둘 다 사용할수 있다. 그 외에 중첩되는 for문이나 배열과 함께 나중에 배울 향상된 for문도 반복문이라고 할수 있으며 break문과 continue문은 (switch-case에 쓰이는 break문은 예외로 두고) 항상 반복문에만 쓰인다는걸 알아두면 좋겠다. 좋은 프로그래머는 상황에 따라서 유도리 있게 적절한 조건문 반복문을 사용한다는걸 명심해야한다고 책에서나 강사님이 그러셨다.

아무튼 다음장에선 우리가 그냥 문법으로 배웠던 클래스가 정말 무엇이며 객체는 또 무엇인지 그리고 같은 자료형을 가진 여러개의 값을 묶어 하나로 합친 객체인 배열과 한 글자 이상의 문자를 표현하는 자료형이자 클래스이자 객체인 String에 대해 알아보겠다.

0개의 댓글