■ 반환타입 선택

원소 시퀀스, 즉 일련의 원소를 반환하는 메서드는 많다. 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를 모두 지원할 수 있게 작성하라
  • 원소의 개수가 많다면, 멱집합의 예처럼 전용 컬렉션을 리턴하는 방법도 고민하라
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기