티스토리 뷰
반응형
자바7까지는 일련의 원소를 반환하는 메서드의 반환 타입으로 컬렉션 인터페이스나 Iterable, 배열을 써왔다.
그런데, 자바8의 스트림 도입 이후 이 선택이 복잡해졌다.
Iterable vs Stream
- 스트림은 반복을 지원하지 않는다. (반환된 스트림을 for-each 반복 X)
- 사실 Stream 인터페이스는 Iterable 인터페이스가 정ㅇ의한 추상 메서드를 전부 포함하고, Iterable 인터페이스가 정의한 방식대로 동작 → 그런데도 for-each로 반복 못하는 이유? Stream이 Iterable을 확장(extends)하지 않아서.
스트림을 반복하기 위한 우회
Stream의 iterator 메서드에 메서드 참조를 건네면 스트림을 반복할 수 있을 것 같다.
그러나 다음 코드는 컴파일 오류가 난다.
// 컴파일 오류 : 타입 추론 한계
for(ProcessHandle ph : ProcessHandle.allProcesses()::iterator) {
}
그렇다면 Iterable로 명시적 형변환을 해준다면?
// 너무 난잡하고 직관성 떨어짐
for(ProcessHandle ph : (Iterable<ProcessHandler>)
ProcessHandle.allProcesses()::iterator) {
}
이를 보완하기 위한 어뎁터 메서드 제공
이 경우에는 타입 추론이 잘 되어 명시적 형변환이 필요 없다.
//Stream<E> 를 Iterable<E>로 중계해주는 어뎁터
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
return stream::iterator;
}
//for-each문으로 스트림 반복 가능
for(ProcessHandle ph : iterableOf(ProcessHandle.allProcesses())) {
}
API가 스트림만 반환하도록 짯을 경우에 위의 코드처럼 중계해주는 어뎁터를 직접 만들 수 있다.
반대 상황도 마찬가지다. API가 Iterable만 반환한다면?
//Iterable<E> 를 Stream<E>로 중계해주는 어뎁터
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), false);
}
Iterator와 Stream 중 무엇을 반환할까?
공개 API를 작성할 때는 사용자 대부분이 한 방식만 사용할거라는 근거가 없다면 두 방식 모두 반환하도록 작성하자.
- Collection 인터페이스는 Iterable의 하위타입이고 stream 메서드도 제공한다. → 그래서 원소 시퀀스를 반환하는 공개 API의 반환 타입에는 Collection이나 그 하위 타입을 쓰는게 최선 ex) Arrays 역시 Arrays.asList와 Stream.of 메서드 지원
- 반환하는 시퀀스 크기가 메모리에 올려도 안전할만큼 작으면 표준 컬렉션 구현체를 반환하는 게 최선 → 이러한 이유로 덩치 큰 시퀀스를 메모리에 올리면 안됨. 이 경우에 전용 컬렉션을 구현하는 방안 검토
- AbstractCollection 을 활용하여 컬렉션 구현체를 작성할때는 contains와 size도 구현해줘야함
결론
원소 시퀀스를 반환하는 메서드를 작성할 때는 Iterable(반복)과 Stream 두 방식을 모두 작성하자.
하지만 가능하면 Iterable의 하위타입이면서 stream 을 지원하는 Collection의 하위타입을 반환하도록 하자.
반환할 컬렉션의 원소 개수가 적다면 ArrayList와 같은 표준 컬렉션 구현체를 반환하라.
아니면 시퀀스 크기가 크다면 전용 컬렉션을 구현하는 것을 고민하라.
반응형
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] 49.매개변수가 유효한지 검사하라 (0) | 2022.04.04 |
---|---|
[Effective Java] 48. 스트림 병렬화는 주의해서 적용하라 (0) | 2022.04.01 |
[Effective Java] 46. 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2022.04.01 |
[Effective Java] 45. 스트림은 주의해서 사용하라 (0) | 2022.04.01 |
[Effective Java] 44.표준 함수형 인터페이스를 사용하라 (0) | 2022.04.01 |
댓글