[아이템 47] 반환 타입으로는 스트림보다 컬렉션이 낫다
2023. 5. 31. 10:44ㆍJava/Effective Java
서론
- 자바 7 까지는 일련의 원소를 반환하는 메서드의 반환 티입으로 컬렉션 인터페이스나 Iterable, 배열을 써왔다.
- 기본은 컬렉션 인터페이스이며, for-each 문에서만 쓰이거나 반환된 원소 시퀀스가 일부 Collection 메서드를 구현할 수 없을 때(주로 contains(Object) 같은)는 Iterable 인터페이스를 썼다.
- 반환 원소들이 기본 타입이거나 성능에 민감한 상황이라면 배열을 썼다.
- 자바 8의 스트림 도입 후 선택이 복잡해졌다.
Stream
- Iterable 인터페이스가 정의한 추상 메서드를 전부 포함할 뿐만 아니라, Iterable 인터페이스가 정의한 방식대로 동작한다.
- 하지만 for-each 로 스트림을 반복할 수 없는 이유는 Iterable 을 확장(extends)하지 않아서이다.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
...
}
public interface BaseStream<T, S extends BaseStream<T, S>>
extends AutoCloseable {
...
}
Collection
- Iterable 하위 타입이며 stream 메서드 제공
- 반복과 스트림을 동시에 지원
public interface Collection<E> extends Iterable<E> {
...
// Stream 메서드 제공
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
스트림을 반복하기 위한 우회
- Stream의 iterator 메서드에 메서드 참조를 건네면?
- 컴파일 오류남
for (ProcessHandle ph : ProcessHandle.allProcesses()::iterator) {
}
- Iterable로 형변환
- 작동은 하지만 난잡하고 직관성이 떨어짐
for (ProcessHandle ph : (Iterable<ProcessHandle>) ProcessHandle.allProcesses()::iterator) {
}
- 어댑터 메서드 제공을 통해 보안
- 이 경우, 자바의 타입 추론이 문맥을 잘 파악하여 어댑터 메서드 안에서 따로 형변환 하지 않아도 된다.
@Test
public void test() {
for (ProcessHandle ph : iterableOf(ProcessHandle.allProcesses())) {
}
}
// Stream<E>를 Iterable<E>로 중개해주는 어댑터
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
return stream::iterator;
}
- 반대의 경우의 어뎁터
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), false);
}
정리
- 원소 시퀀스를 반환하는 메서드를 작성할 때 Iterable 과 Stream 두 방식 모두 작성하자
- 하지만 가능하면 Iterable 하위타입이면서 Stream을 지원하는 Collection 의 하위 타입을 반환하도록 하자.
- 반환할 컬렉션의 원소 개수가 적다면 ArrayList와 같은 표준 컬렉션 구현체를 반환하라
- 시퀀스 크기가 크다면 전용 컬렉션을 구현하는 것을 고민하라
'Java > Effective Java' 카테고리의 다른 글
[아이템 48] 스트림 병렬화는 주의해서 사용하라 (0) | 2023.05.31 |
---|---|
[아이템 46] 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2023.05.30 |
[아이템 45] 스트림은 주의해서 사용하라 (1) | 2023.05.17 |
[아이템 43] 람다보다는 메서드 참조를 사용하라 (0) | 2023.05.13 |
[아이템 42] 익명 클래스보다는 람다를 사용하라 (0) | 2023.05.12 |