스트림은 반복을 지원하지 않는다. Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메소드를 전부 포함할 뿐만 아니라 Iterable 인터페이스가 정의한 방식대로 동작한다. 하지만 Stream이 Iterable을 extend하지 않아서 반복할 수 없다. 이럴 경우 Stream으로 반복을 위한 어뎁터를 사용해야 한다. 반대로 Iterable만 반환하면 스트림 파이프라인에서 처리할 수가 없다. 이 또한 역으로 어뎁터를 만들어야 한다. 다음은 어뎁터에 해당하는 코드이다.
하지만 API를 작성할 때는 스트림 파이프라인을 사용하려는 사용자와 반복문에서 사용하려는 사용자를 모두 배려해야한다. 이럴때는 Collection 인터페이스를 사용하면 된다. Collection 인터페이스는 Iterable의 하위 타입이고 stream 메소드도 제공하기 때문이다. 따라서 원소 시퀀스를 반환하는 공개 API의 반환 타입에는 Collection이나 그 하위 타입을 쓰는게 일반적으로 최선이다.하지만 단지 컬렉션을 반환한다는 이유로 덩치 큰 시퀀스를 메모리에 올리면 안된다. 반환할 시퀀스가 크지만 표현을 간결하게 할 수 있다면 전용 컬렉션을 구현하는 편이 좋다. 다음은 주어진 집합의 멱집합을 반환하는 컬렉션이다.
publicstaticfinal <E> Collection<Set<E>> of(Set<E> s) { List<E> src = newArrayList<>(s); if(src.size() > 30) thrownewIllegalArgumentException("maximum elements must be under 30");
returnnewAbstractList<Set<E>>() { @Override public Set<E> get(int index) { Set<E> result = newHashSet<>(); for(inti=0; index != 0; i++, index>>=1) if((index & 1) == 1) result.add(src.get(i)); return result; }
for (inti=0; i < l.size(); i++) for(intj= i + 1; j <= l.size(); j++) System.out.println(l.subList(i,j));
Conclusion
원소 시퀀스를 반환하는 메소드를 작성할 때는 스트림과 iterable을 모두 지원하는 콜렉션을 통해 반환하라. 원소의 개수가 많다면 위의 멱집합과 같은 예 처럼 전용 콜렉션을 만드는것이 방법이다. 콜렉션 반환이 불가능하다면 스트림과 iterable중 자연스러운것을 반환하라.