반환 타입으로는 스트림보다 컬렉션이 낫다
- 자바 7까지는 일련의 원소를 반환하는 메서드 반환 타입으로 Collection, Set, List 등의 컬렉션 인터페이스, Iterable, 배열을 사용해 왔다.
- 선택하는 우선순위
- 컬렉션 인터페이스
- for-each 문에서만 쓰이거나 반환된 원소 시퀀스가 일부 Collection 메서드를 구현할 수 없을 때는 Iterable
- 반환 원소들의 기본 타입이거나 성능에 민감한 상황이라면 배열
- 자바8 스트림이 등장하면서 이런 선택이(시퀀스의 반환타입을 정하는 것) 복잡해졌다.
😵💫 스트림은 반복을 지원하지 않는다.
- 아이템45에서 이야기했듯이 스트림은 반복을 지원하지 않는다. 따라서 스트림과 반복을 알맞게 조합해야 좋은 코드가 나온다.
- API를 스트림만 반환하도록 짜놓으면 반환된 스트림을 for-each로 반복하길 원하는 사용자는 당연히 불만을 토로할 것이다.
재미난 사실?
- 사실 Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함할 뿐만 아니라, Iterable 인터페이스가 정의한 방식대로 동작한다.
- 그럼에도 for-each로 스트림을 반복할 수 없는 이유는 Stream이 Iterable을 확장하지 않기 때문이다.
// 자바 타입 추론의 한계로 컴파일 되지 않는다.
Stream<String> names = Stream.of("김병연","김수미","김형욱","이연우","이용훈");
for (String name : names::iterator) {
}
// 이 오류를 잡으려면 메서드 참조를 매개변수화 된 Iterable로 적절히 형변환을 해야한다.
for (String name : (Iterable<String>)names::iterator) {
}


-
위의 수정된 코드는 동작은 하지만 실전에 쓰기에는 너무 난잡하고 직관성이 떨어진다.
- 다행히 어댑터 메서드를 사용하면 상황이 나아진다!
- 자바는 어댑터라는 메서드를 제공하지 않지만 쉽게 만들어낼 수 있다. 어댑터 메서드를 이용하면 타입 추론이 문맥을 잘 파악하여 어댑터 메서드 안에서 따로 형변환하지 않아도 된다.
-
adapter pattern
- 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
- 어댑터를 사용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.
-
스트림 파이프 라인에서만 쓰인다면 > Stream 반환
-
반복문에서만 쓰인다면 > Iterable 반환
-
여러 상황을 고려하여 두가지 방법 모두 구현해야 한다.
- 사용자 대부분이 한 방식만 사용할 거라는 근거가 없기 때문이다.
public static<E> Iterable<E> iterableOf(Stream<E> stream) {
return stream::iterator;
}
// 어댑터를 사용하면 어떤 스트림도 foreach 문으로 반복할 수 있다.
for (String name : Adapters.iterableOf(names)) { ... }
// Stream을 Iterable로 바꿔준 것처럼 반대도 구현해야한다.
public static <E> Steram<E> streamOf(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), flase);
}
- Collection 인터페이스는 Iterable의 하위 타입이고 Stream 메서드도 제공하기 때문에 반복과 스트림을 동시에 지원한다.
- 원소 시퀀스를 반환하는 공개 API 반환 타입에는 Collection이나 그 하위 타입을 쓰는게 일반적으로 최선이다.
- Arrays → Arrays.asList(Iterable), Stream.of(Stream)
🥸 표현을 간결하게 할 수 있다면 전용 컬렉션을 구현하자
- 단지 컬렉션을 반환한다는 이유로 덩치 큰 시퀀스를 메모리에 올려서는 안된다.
- 반환할 시퀀스가 크지만 표현을 간결하게 할 수 있다면 전용 컬렉션을 구현하는 방안을 검토해야 한다.
- 예를 들어 주어진 집합의 멱집합(한 집합의 모든 부분집합을 원소로 하는 집합)을 반환하는 상황에서 원소의 개수가 n개면 멱집합의 원소 개수는 2^n-1 개가 된다.