[Effective Java] 전통적인 for문 보다는 for-each문을 사용하라

들어가며

전통적인 for문보다 for-each문이 간결할 때가 많다. for-each문은 Iterable 인터페이스를 구현한 객체라면 무엇이든 순회할 수 있다. 다음 코드를 보자. 다음 코드는 주사위 원소를 순회하며 주사위를 두번 던졌을 때 조합할 수 있는 숫자를 출력한다. 이 코드에는 버그가 있다.

1
2
3
4
5
6
7
enum Face { ONE, TWO, THREE, FOUR, FIVE, SIZ }
...
Collection<Face> faces = EnumSet.allOf(Face.class);

for(Iterator<Face> i = faces.iterator(); i.hasNext(); )
for(Iterator<Face> j = faces.iterator(); j.hasNext(); )
System.out.println(i.next(); + " " + j.next());

i.next()를 계속 호출하니 원하는 대로 동작하지 않는다. 위 코드를 전통적인 for문으로 바꾸려면 다음과 같다.

1
2
3
4
5
for(Iterator<Face> i = faces.iterator(); i.hasNext(); ) {
Face face = i.next();
for(Iterator<Face> j = faces.iterator(); j.hasNext(); )
System.out.println(face + " " + j.next());
}

이를 for-each로 고치면 다음과 같다.

1
2
3
for(Face face1 : faces)
for(Face face2 : faces)
System.out.println(face1 + " " + face2);

하지만 for-each문을 사용할 수 없는 상황도 존재한다.

  1. 파괴적인 필터링(destructive filtering)
    • 컬렉션을 순회하면서 선택된 원소를 제거해야 한다면 반복자의 remove 메소드를 호출해야 한다. 자바 8부터는 Collection의 removeIF 메소드를 통해 컬렉션을 명시적으로 순회하는 일을 피할 수 있다.
  2. 변형(transforming)
    • 리스트나 배열을 순회하면서 그 원소의 값 일부 혹은 전체를 교체해야 한다면 리스트의 반복자나 배열의 인덱스를 사용해야 한다.
  3. 병렬 반복(parallel iteration)
    • 여러 컬렉션을 병렬로 순회해야 한다면 각각의 반복자와 인덱스 변수를 사용해 엄격하고 명시적으로 제어해야 한다.
Author: Song Hayoung
Link: https://songhayoung.github.io/2020/08/19/Languages/Effective%20JAVA/item58/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.