티스토리 뷰

728x90
반응형

반환 타입으로는 스트림보다 컬렉션이 낫다


  • 원소 시퀀스, 즉 일련의 원소를 반환하는 메서드는 수 없이 많았습니다. 자바 8이전까지는 Collection, Set, List와 같은 컬렉션 인터페이스 또는 Iterable이나 배열을 사용했습니다. 하지만 자바 8이후로 Stream이 등장하며 복잡해졌습니다.
  • for-each 문에서만 사용이 되거나 반환된 원소 시퀀스가 일부 Collcetion 메서드를 구현할 수 없는 경우에는 Iterable 인터페이스를 사용하곤 했습니다. 그리고 반환 원소들이 기본 타입이거나 성능에 민감한 상황이라면 배열을 사용했습니다.

 

💡 반복을 지원하지 않는 Stream

  • Stream과 Stream의 상위 객체인 BaseStream은 모두 Iterable 인터페이스를 구현하거나 상속하지 않습니다. 그럼에도 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함하고 Iterable 인터페이스가 의도하는 방식으로 동작합니다.
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable { 

	...
}

public interface Stream<T> extends BaseStream<T, Stream<T>> { 

}

 

💡 BaseStream의 iterator 메서드 ?

  • BaseStream 인터페이스의 iterator 메서드를 사용하면 for-each를 사용할 수 있지 않을까?

 

  • 막상 사용을 하면 컴파일 오류가 발생합니다.

 

  • 형변환을 하여 컴파일 오류가 없어진것을 볼 수 있습니다. 하지만 실전에서는 사용하기 어렵고 직관적이지 않습니다. 이런 경우 어댑터 메서드를 사용하면 문제를 해결할 수 있습니다.

 

💡 어댑터 메서드

  • 코드가 직관적이고 명시적으로 바뀌었습니다.
public class Example {

    public static void main(String[] args) {

        Stream<String> stream = Stream.of("A", "C", "D");
        List<String> list = Arrays.asList("A", "C", "D");

        for (String s : iterableOf(stream)) {
            System.out.println(s);
        }

        streamOf(list).forEach(System.out::println);
    }

    // return For-each
    public static <E> Iterable<E> iterableOf(Stream<E> stream) {
        return stream::iterator;
    }

    // return Stream
    public static <E> Stream<E> streamOf(Iterable<E> iterable) {
        return StreamSupport.stream(iterable.spliterator(), false);
    }
}

 

💡 Collection vs Stream

  • Collection - Collection 인터페이스는 Iterable 인터페이스의 하위 타입이고 stream 메서드도 제공하니 일반적으로 Collection을 반환하는게 좋습니다. 하지만 Collectio의 각 원소는 메모리에 올라가니, 시퀀스의 크기가 크다면 고민해보는게 좋습니다.
public interface Iterable<T> { 

}
public interface Collection<E> extends Iterable<E> { 

}

 

  • Stream - 컬렉션의 contains와 size를 시퀀스의 내용을 확정하기 전까지 구할 수 없는 경우(실제 반복을 돌려 보기전까지 무엇이 얼마나 들어갈지 예측이 불가능한 경우) Stream을 반환하는게 좋습니다.

 

 

 

728x90
반응형