#47 반환 타입으로는 스트림보다 컬렉션이 낫다
Collection interface, Iterable interface, Array 반복문을 처리하기 위해서는 for-each를 이용할 수 있습니다.
Stream 반복문을 처리하기 위해서는 forEach(Consumer<? super T> action) 같은 API를 이용할 수 있습니다.
이 두 가지의 차이점과 반환 타입으로 Collection이 더 나은 이유에 대해 알아보겠습니다.
반환 타입이 Collection인 경우(getAllNameList()) for-each문이나 Stream으로 변환 후에 반복문을 처리할 수 있습니다.
반환 타입이 Stream인 경우(getAllNameStream()) for-each문으로 반복문을 처리할 수 없습니다.
Stream이 Iterable를 확장(extends) 하지 않았기 때문입니다.
다행히도? Stream은 Iterable interface가 정의한 추상 메서드를 전부 가지고 있고 동일한 방식으로 동작하고 있습니다.
따라서 위에서 처럼 메서드 참조(Stream::iterator)를 적절히 형 변환(Iterable <String>)해주면 for-each문을 쓸 수 있습니다.
하지만 Collection을 이용한 for-each문보다는 성능적으로 더 떨어질 수 있습니다.
반환받는 입장에선 반복문을 for-each로 처리하길 원하지만, Stream으로 반환받는다면 위처럼 지저분하게 처리해야 합니다.
그리고 Collection의 경우 Iterable의 하위 타입이고 stream 메서드도 지원하고 있습니다.
Arrays 역시 asList와 Stream.of 메서드로 손쉽게 반복문과 Stream을 지원할 수 있습니다.
반복문을 처리하기 위한 옵션이 더 많은 Collection이 더 낫습니다.
Collection으로 반환하기 위해 ArrayList나 HashSet 같은 표준 Collection 구현체를 반환할 수 도 있지만, 만약 시퀀스가 크고 표현을 간결하게 할 수 있다면 Custom 한 Collection이 더 낫습니다.
예를 들어, 멱집합(한 집합의 모든 부분집합을 원소로 하는 집합)을 구현하기 위해 AbstractCollection을 이용할 수 있습니다.
{a, b, c}의 멱집합 : {{a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}}
AbstractCollection을 이용하면 Iterable용 메서드 외에 contain과 size 메서드 두 개만 더 구현하면 됩니다.
만약 표준/Custom Collection 둘 다 반환하기 힘들다면, Iterator나 Stream을 반환하는 편이 더 낫습니다.
Stream이나 Collection 둘 사이의 성능적 이슈 보다는, 반환받는 입장에서 선택지가 더 많은 Collection이 사용성 측면에서 더 낫다는 내용이였습니다.
Collection을 반환하러 노력하고, 만약 힘들다면 Iterator나 Stream을 반환하자입니다.