for

지금 배울 for문도 앞서 배운 while문과 비슷합니다. 차이를 살펴보자면, while문은 반복에 사용되는 변수를 초기화하는 초기식, 빠져나올 조건을 결정하는 조건식, 빠져나오기 위해 반복에 사용되는 변수를 증가 또는 감소시키는 증감식이 흩어져 있습니다. for문은 초기식, 조건식, 증감식이 세미콜론을 구분으로 하여 모두 붙어있습니다.

int i = 0; // 초기식

while (i < 5) { // 조건식
	System.out.println(i);
    i++; // 증감식
}
int i;

for (i = 0; i < 5; i++) // 초기식; 조건식; 증감식
	System.out.println(i);

보기에도 while문보다 for문이 훨씬 간결하죠? for문에서 반복에 사용될 변수는 초기식에서 선언할 수 있어 아래와 같이 작성할 수도 있습니다. 물론 초기식에서 선언하면 변수의 생존범위 때문에 for문 외부에서는 해당 변수에는 접근할 수 없습니다.

for (int i = 0; i < 5; i++) // 초기식; 조건식; 증감식
	System.out.println(i);

이 for문은 보통 반복 횟수를 알고 있는 경우에 많이 사용하고, while문은 루프를 돌다가 어떤 조건을 만족할 때 결과를 얻어 루프를 탈출할 때 많이 사용됩니다. 자기가 편한 반복문을 선택하세요. for문으로 할 수 있는 것을 while문으로도 할 수 있고, while문으로 할 수 있는 것을 for문으로도 할 수 있습니다.

다음 예제를 한 번 살펴보도록 합시다.

public class ForExamples {
	public static void main(String[] args) {
		for (int i = 1; i <= 10; i++) {
			System.out.println(i + "회 반복했습니다.");
		}
	}
}

결과를 확인하고 코드로 돌아가, 예제의 3행을 보시면 for문이 사용된 것을 보실 수가 있습니다.

for (①초기식; ②조건식; ③증감식) {
	④실행 문장;
}

여기서 초기식이란 처음에 한 번만 실행되며, 제어 변수를 여기서 초기화합니다. 여기서 제어 변수(control variable)란 반복의 횟수를 결정짓는 변수로 반복문을 제어하는 역할을 합니다. 그리고 두 번째, 조건식은 while문의 조건식과 동일합니다. 이 조건이 거짓이 되면 루프를 빠져나옵니다. 세 번째, 증감식은 루프 탈출을 위해서 제어 변수를 증가 또는 감소시키는 등의 작업이 이곳에서 이루어집니다. 위에서 보시다시피 초기식, 조건식, 증감식은 세미콜론(;)으로 구분합니다. for문의 실행 흐름을 순서도로 나타내면 아래와 같습니다.

위에서 볼 수 있듯이, 초기화가 처음에 한번 이루어지고 그 다음부터는 조건식 검사, for문 내부의 문장 실행, 증감식의 반복입니다. 그러다가 조건식이 거짓이 되면 탈출하는 흐름을 가지고 있습니다. 이해가 되셨나요?

초기식, 조건식, 증감식의 생략

for문에서 초기식을 생략할 수도 있고, 조건식을 생략할 수도 있고, 증감식을 생략할 수도 있습니다. 심지어 세 개를 다 생략할 수도 있습니다. 아래와 같이 작성하면 조건식이 생략되어 있으므로 무한 루프에 빠지게 됩니다.

public class ForExamples {
	public static void main(String[] args) {
		for (;;) {
			System.out.println("루프를 돌고 있습니다.");
		}
	}
}

콤마의 사용

아래와 같이 초기식에서 여러 개의 변수를 선언하거나 초기화할 때 콤마(,)를 사용할 수 있습니다. 증감식도 마찬가지로 콤마를 사용하여 여러 개의 제어 변수를 증가시키거나 감소시킬 수 있습니다.

for (int i = 0, j = 0; i + j < 100; i++, j++) {
	// ...
}

초기식이나 증감식에는 본래의 역할과는 무관한 문장을 삽입할 수 있으나 가독성을 크게 해치므로 잘 사용하지 않습니다.

for (int i = 0; i < 10; i++, System.out.println(i));

continue

continue문을 만나면 현재 반복을 마치고 다음 반복으로 건너뜁니다. continue는 반복문(while, do~while, for)에서 사용할 수 있습니다. 이해를 돕기 위해서 아래 예제를 함께 살펴보도록 하겠습니다.

public class ForExamples {
	public static void main(String[] args) {
		for (int i = 1; i < 20; i++) {
			// 4의 배수는 출력을 건너뛴다.
			if (i % 4 == 0)
				continue;
			System.out.println(i);
		}
	}
}

코드를 살펴봅시다. 5행의 조건을 만족하면 6행의 continue문이 실행됩니다. 즉 'i를 4로 나눈 뒤에 나머지가 0이라면 continue문을 실행한다.'란 말이 됩니다. 흐름을 살펴보면 i의 값이 차례대로 증가하다가 4가 되는 순간 5행의 조건식이 참이 되므로 continue문을 실행하게 됩니다.

위와 같이 continue문을 만나면 현재 반복을 마치고 다음 반복의 준비를 하기 위해서 증감식으로 건너뜁니다. 여기서 i의 값은 5가 되고 조건식으로 이동하여 조건을 검사하고, 다시 for문 내부로 들어가는 흐름을 가지고 있습니다. 이를 while문으로 다시 작성하면 아래와 같을 것입니다.

public class ForExamples {
	public static void main(String[] args) {
		int i = 1;
		
		while (i < 20) {
			// 4의 배수는 출력을 건너뛴다.
			if (i % 4 == 0) {
				i++;
				continue;
			}
			System.out.println(i);
			i++;
		}
	}
}

break

break문은 switch문에서 본 적이 있습니다. 그때는 switch문 밖을 벗어나는 데 사용됐지만, 이번에는 반복문을 벗어나고 싶을 때 사용합니다. 아래의 예제는 무한 루프에 break문을 사용한 예제입니다.

public class ForExamples {
	public static void main(String[] args) {
		int i = 0;
		
		while (true) {
			if (i == 50) {
				break;
			}
			System.out.println(i);
			i++;
		}
	}
}

의도적으로 무한 루프를 만들기 위해 5행에서 while문의 조건식에 true를 적었습니다. 6행에선 i가 50일 경우에 반복문을 탈출할 수 있게끔 break를 걸었습니다.

반복이 진행되면서 i의 값이 1씩 증가하며 50이 되는 순간 6행의 조건식이 참이 되어 break문을 만나고 반복문을 빠져나옴을 볼 수 있습니다. 

break문과 레이블

이 부분은 그냥 쉬어가는 구간이라고 생각해도 됩니다. 가볍게 봐주세요. 여기서 레이블(label, 혹은 라벨)은 소스 코드에서 특정 위치를 나타내는 일종의 표시입니다. 보통 아래와 같이 레이블의 이름 뒤에 콜론(:)을 붙여서 표현하며, 이어서 블록({}), 반복문, 조건문 등의 다양한 문장이 올 수 있습니다.

first:
for (int i = 0; i < 10; i++) {
	// ...
	fourth:
	for (int j = 0; j < 10; j++) {
		// ...
		if (...) {
			continue first; // continue문도 가능하다.
		}
		// ...
	}	
}

second: {
	third: {
		// ...
		break second; // 이렇게 second 레이블을 빠져나올 수도 있다.
		// ...
	}
	// ...
}

보통 레이블이 없는 break문은 자신을 둘러싸는 반복문(while, do, for)이나 switch문을 탈출하기 위해 사용되지만, 아래와 같이 레이블을 지정하여 내부 반복문(inner)이 아닌 외부 반복문(outer)을 탈출할 수도 있습니다. 하지만 이러한 방법은 코드가 조금이라도 복잡해지거나, 레이블이 약간이라도 늘어나면 실행 흐름을 파악하기가 어려워집니다. 따라서 이러한 레이블은 거의 사용되지 않으며 레이블의 존재조차 모르는 개발자도 종종 있습니다. 이런 방법을 사용하지 않아도 대체할 수 있는 더 좋은 방법들(메서드로 대체 등)이 있기 때문입니다.

outer: for (int i = 0; i < n; i++) {
	// ...
	inner: for (int j = 0; j < m; j++) {
		// ...
		break outer;
	}
}

다중 반복문

여태까지 우리가 배운 반복문은 while, do~while, for문이 있었습니다. 이것을 서로 중첩시켜 아래와 같이 반복문 안에서 또 하나의 반복문을 삽입할 수 있습니다. 제한없이 반복문을 중첩시킬 수 있지만 3중 이상의 반복문은 잘 사용하지 않습니다. 중첩이 깊어질수록 실행 시간이 기하급수적으로 증가하고 코드의 가독성을 해치기 때문입니다.

직접 다중 반복문을 사용해 보도록 하겠습니다. 아래는 구구단을 출력하는 예제입니다.

public class ForExamples {
	public static void main(String[] args) {
		for (int i = 2; i < 10; i++) {
			for (int j = 1; j < 10; j++) {
				System.out.println(i + " * " + j + " = " + i * j);
			}
		}
	}
}

코드로 돌아가서, 3~6행을 보면 다중 반복문이 쓰인 것을 확인할 수 있습니다. 외부 for문은 단 한 번만 실행되지만, 내부 for문은 외부 for문의 각 반복마다 실행됩니다. 이를 그림으로 표현하면 아래와 같습니다.

'프로그래밍 관련 > 자바' 카테고리의 다른 글

13편. 객체와 클래스(Objects and Classes)  (57) 2012.08.10
12편. 메서드(Method)  (27) 2012.08.09
10편. 반복문 (1)  (6) 2012.07.31
9편. 제어문 (2)  (20) 2012.07.30
8편. 제어문 (1)  (16) 2012.07.30