본문으로 바로가기
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.


자바 1.5 버전 이전에서는 컬렉션을 순회할 때 아래의 숙어를 따르는 것이 바람직 했다.


1
2
3
for(Iterator i = c.iterator(); i.hasNext();) {
    doSomething((Element)i.next()); //1.5 이전에는 제네릭이 없었다.
}


1.5 때는 지금과 마찬가지로 아래와 같이 배열을 순회했었다.

1
2
3
for(int i = 0; i < a.length; i++) {
    doSomething(a[i]);
}



위의 숙어들은 while문보다는 낫지만 반복자나 첨자 변수가 성가신다. 또한 오류가 생길 가능성도 있다. 반복자는 세번 등장하고 첨자 변수는 네번 등장한다. 실수로 다른 변수를 이용할 가능성이 있는 것이다. 그리고 그런 오류는 컴파일 과정에서 탐지되지 않는다.

자바 1.5버전 부터 도입된 for-each문은 성가신 코드를 제거하고 반복자나 첨자 변수를 완전히 제거해서 오류 가능성을 없앤다.

for-each문에서 : 기호는 안에 있는(in) 이라고 읽는다. 따라서 아래 순환문은 strs안에 있는 각각에 대해서 라고 읽으면 된다.


1
2
3
4
5
String[] strs = {"ktko""kkt""kyungtae""Ko KyungTae"};
 
for(String str : strs) {
    System.out.println(str);
}



for-each문의 장점은 여러 컬렉션에 중첩되는 순환문을 만들어야 할 때 더 빛난다. 한 가지의 예를 들자면 아래 예제에서 주사위를 두 번 던졌을 때 나올 수 있는 모든 조합을 출력하려고 하는데 예상과는 달리 {ONE,ONE}, {TWO,TWO}, {THREE, THREE} ... {SIX, SIX} 의 결과값이 나온다. 원래는 36가지의 조합을 출력했어야 했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test {
    enum Face{ ONE, TWO, THREE, FOUR, FIVE, SIX};
    
    public static void main(String[] args) {
        Collection<Face> faces = Arrays.asList(Face.values());
        
        for(Iterator<Face> i = faces.iterator(); i.hasNext();) {
            for(Iterator<Face> j = faces.iterator(); j.hasNext();) {
                System.out.println(i.next() + " " + j.next());
            }
        }
    }
}




for-each문을 중첩해서 프로그램을 짜면 이 문제는 쉽게 사라진다. 그 결과 만들어진 코드는 아주 간결하다.
1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
    enum Face{ ONE, TWO, THREE, FOUR, FIVE, SIX};
    
    public static void main(String[] args) {
        Collection<Face> faces = Arrays.asList(Face.values());
        
        for(Face face1 : faces) {
            for(Face face2 : faces)
            System.out.println(face1 + "," + face2);
        }
    }
}



for-each문은 전통적인 for문에 비해 명료하고 버그 발생 가능성도 적으며, 성능도 for문에 뒤지지 않는다. 그러니 가능하다면 항상 사용해야 한다. 그러나 불행히도 아래의 세 경우에 대해서는 for-each 문을 적용할 수 없다.


1. 필터링(filtering) - 컬렉션을 순회하다가 특정한 원소를 삭제할 필요가 있다면, 반복자를 명시적으로 사용해야 한다. 반복자의 remove 메서드를 호출해야 하기 때문이다.


2. 변환(transforming) - 리스트나 배열을 순회하다가 그 원소 가운데 일부 또는 전부의 값을 변경해야 한다면, 원소의 값을 수정하기 위해서 리스트 반복자나 배열 첨자가 필요하다.


3. 병렬 순회(parallel iteration) - 여러 컬렉션을 병렬적으로 순회해야 하고, 모든 반복자나 첨자 변수가 발맞춰 나아가도록 구현해야 한다면 반복자나 첨자 변수를 명시적으로 제어할 필요가 있을 것이다.