■ 반환타입 선택
원소 시퀀스, 즉 일련의 원소를 반환하는 메서드는 많다. Collection, List, Set과 같은 컬렉션 인터페이스, 혹은 Iterable이나 배열을 사용했다. 자바 8에서는 스트림이 도입되면서 선택지가 복잡해졌다.
스트림은 반복을 지원하지 않는다. 따라서 스트림과 반복을 알맞게 조합해야 좋은 코드가 나온다. 여기서 재밌는 사실 하나는 Stream인터페이스는 Iterable 인터페이스의 추상 메서드를 모두 정의해 놓았지만 Iterable을 확장하지 않았다는 문제가 있다.
어댑터 메서드를 사용하면 스트림을 iterate로 변경할 수 있다.
//Stream<E>를 Iterable<E>로 중개해주는 어댑터
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
return stream::iterator;
}
반대로 API가 Iterable을 받아서 스트림을 반환하는 어댑터도 구현이 가능하다.
//Iterabel<E>를 Stream<E>로 중개해주는 어댑터
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), false);
}
객체 시퀀스를 반환하는 메서드를 작성할 때 오직 스트림 파이프라인에서만 쓰일 걸 안다면 스트림을 반환하고, 반환된 객체들이 반복문에서만 쓰일 걸 안다면 Iterable을 반환하자. 하지만 공개 API에서는 2개다 지원하는게 좋다.
■ Collection VS Stream
Collection
- Collection 인터페이스는 Iterable 인터페이스의 하위 타입이고 stream 메서드도 제공하니 일반적으로는 Collection을 반환하는편이 좋다.
- 하지만 Collection의 각 원소는 메모리에 올라가므로, 시퀀스의 크기가 크다면 고민해보는 것이 좋다.
Stream
- 컬렉션의 contains와 size를 시퀀스의 내용을 확정하기 전 까지 구할 수 없는 경우(i.e. 실제 반복을 돌려보기 전 까지는 무엇이 얼마나 들어갈지 예측이 불가능한 경우)에는 Stream을 반환하는 것이 좋다.
■ 정리
- Stream이나 Iterable을 리턴하는 API에는 Stream <-> Iterable로 변환할 수 있도록 어댑터 메서드가 필요하다.
- 어댑터는 클라이언트 코드를 어수선하게 만들고 더 느리다.
- 원소 시퀀스를 반환하는 메서드를 작성할 때는 Stream, Iterator를 모두 지원할 수 있게 작성하라
- 원소의 개수가 많다면, 멱집합의 예처럼 전용 컬렉션을 리턴하는 방법도 고민하라
'Effective Java' 카테고리의 다른 글
[Effective Java] 아이템49 매개변수가 유효한지 검사하라 (0) | 2021.07.04 |
---|---|
[Effective Java] 아이템48 스트림 병렬화는 주의해서 적용하라 (0) | 2021.06.29 |
[Effective Java] 아이템46 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2021.06.28 |
[Effective Java] 아이템45 스트림은 주의해서 사용하라 (0) | 2021.06.27 |
[Effective Java] 아이템44 표준 함수형 인터페이스를 사용하라 (0) | 2021.06.27 |