Java Iterator Pattern on Colletions

The Iterator pattern

Iterator 패턴은 Collection을 탐색하는 방법과 클라이언트가 수행할 작업을 분리하는 GoF의 패턴 중 하나입니다. index, cursor, enumeration 등으로도 불립니다.

Iterator는 Active 또는 Passive한 형태로 나뉩니다. Active Iterator는 클라이언트가 Iterator를 생성하고, 다음 아이템의 존재 여부를 확인하고, 다음 아이템을 얻는 작업을 합니다. 반면, Passive Iterator는 이 작업을 내부적으로 수행합니다.

Java는 Iterator 패턴을 이용하여 Collection을 탐색합니다. Active에서 Passive한 형태로 발전했습니다.

Enumeration

초기 Java 1.0 때는 Collection에 Vector와 Hashtable만 있었고, Enumeration을 이용해 탐색하였습니다. Java 5 이후부터는 enum 타입과 헷갈리기 때문에 위 클래스들을 사용하지 않는 것이 좋습니다.

1
2
3
4
5
6
7
8
9
10
Vector names = new Vector();
// ... add some names to the collection
Enumeration e = names.elements();
while (e.hasMoreElements())
{
String name = (String) e.nextElement();
System.out.println(name);
}

Iterator

Java 1.2부터 Collections Framework를 설계하면서 Iterator라는 명확한 이름으로 구현되었습니다.

1
2
3
4
5
6
7
8
9
10
List names = new LinkedList();
// ... add some names to the collection
Iterator i = names.iterator();
while (i.hasNext())
{
String name = (String) i.next();
System.out.println(name);
}

Generics and the Enhanced for-loop

Java 5부터는 Iteratable 인터페이스를 구현한 객체라면 for-each 구문을 이용할 수 있습니다. 기존에는 Active한 형태였지만 이제는 Passive한 형태로 진화하고 있는 과도기입니다. Java 7에서는 Diamond Operator를 이용해 타입 추론이 가능합니다.

1
2
3
4
5
6
7
List<String> names = new LinkedList<String>(); // Java 5
List<String> names = new LinkedList<>(); // Java 7
// ... add some names to the collection
for (String name : names)
System.out.println(name);

forEach

Java 8에서는 Iterable 인터페이스에 default 메소드로 forEach 메소드를 제공합니다. forEach 메소드의 인자로 lambda 표현식이 들어갑니다. 기존에는 ‘반복’이라는 개념을 명시적으로 표현했다면, forEach는 이것을 암묵적으로 표현합니다.

1
2
3
4
5
List<String> names = new LinkedList<>();
// ... add some names to the collection
names.forEach(name -> System.out.println(name));

Stream API

Java 8에서는 stream 메소드를 이용해 컬렉션을 다룰 수 있습니다. filter(), distinct(), sorted(), map() 등의 중간 연산과 count(), average(), sum(), max(), forEach() 등의 종단 연산을 연결할 수 있습니다. 각 아이템에 대한 연산을 병렬화 하려면 parallelStream() 메소드를 이용하면 됩니다.

1
2
3
4
5
6
7
List<String> names = new LinkedList<>();
// ... add some names to the collection
long count = names.stream()
.filter(name -> name.startsWith("A"))
.count();

Performance

Active와 Passive 사이에는 큰 차이가 없습니다.
LinkedList, LinkedHashSet은 stream과 parallelStream 사이에는 큰 차이가 없습니다.(순차 참조 자료 구조)
ArrayList, TreeSet, HashSet은 parallelStream이 성능이 좋습니다.(직접 참조 자료 구조)

Reference

Iterating over collections in Java 8

Share Comments