58. 전통적인 for 문보다는 for-each 문을 사용하라

전통적인 for문보다 for-each문이 간결할 때가 많다. for-each문은 Iterable 인터페이스를 구현한 객체라면 무엇이든 순회할 수 있다. 다음 코드를 보자.

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()를 계속 호출하기 때문에 결과값은 "ONE ONE"부터 "SIX SIX"가 출력된다. 이는 의도한 바가 아니다. 위 코드를 해결하기 위해서는 바깥 반복문에 바깥 원소를 저장하는 변수를 하나 추개햐아 한다.

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 문을 중첩하는 것으로 이 문제는 간단히 해결할 수 있다. 코드도 놀랄 만큼 간단해진다.

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

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

  • 파괴적인 필터링(destructive filtering)
    • 컬렉션을 순회하면서 선택된 원소를 제거해야 한다면 반복자의 remove 메소드를 호출해야 한다. 자바 8부터는 Collection의 removeIF 메소드를 통해 컬렉션을 명시적으로 순회하는 일을 피할 수 있다.
  • 변형(transforming)
    • 스트나 배열을 순회하면서 그 원소의 값 일부 혹은 전체를 교체해야 한다면 리스트의 반복자나 배열의 인덱스를 사용해야 한다.
  • 병렬 반복(parallel iteration)
    • 여러 컬렉션을 병렬로 순회해야 한다면 각각의 반복자와 인덱스 변수를 사용해 엄격하고 명시적으로 제어해야 한다.

전통적인 for 문보다 for-each 문은 더 명료하고 유연하고 버그를 예방해준다.
성능 저하도 없다. 가능한 모든 곳에서 for문이 아닌 for-each 문을 사용하자.

좋은 웹페이지 즐겨찾기