반응형
일련의 원소를 반환하는 메서드
- 반환 타입으로 Collection, Set, List, Iterable, Array 등 다양하게 사용 가능하다.
- Java8에서 Stream 등장으로 복잡한 일이 발생하기 시작했다.
반복(iteration)을 지원하지 않는 Stream
stream만 반환하는 API
❗
여기서 의미하는 for-each는 stream().forEach()가 아니다.
for(String l : list) { ... } 를 의미합니다.
❓ Stream과 Iterable
Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함한다.
이들은 Iterable 인터페이스가 정의한 방식대로 동작한다.
그럼에도 for-each가 불가능한건 Stream이 Iterable을 확장(extend)하지 않아서이다.
// Stream 인터페이스는 Iterable을 extend하지 않는다.
public interface Stream<T> extends BaseStream<T, Stream<T>> {
// ...
}
// 혹시나 해서 BaseStream도 봤지만 역시나 extend하지 않는다.
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
Iterator<T> iterator();
// ...
}
// for-each가 가능한 Collection은 Iterable을 extend 한다.
public interface Collection<E> extends Iterable<E> {
// ...
}
그렇다면 Stream과 Iterable을 같이 사용하는 방법을 생각해보겠다.
// ProcessHandle.allProcess()의 return 값: Stream<ProcessHandle>
// ProcessHandle: 기본 프로세스를 식별하고 제어하는 인터페이스
for(ProcessHandle processHandle : (Iterable<ProcessHandle>)ProcessHandle.allProcesses()::iterator){
// 프로세스 처리
}
저 끔찍한 형변환이 보이는가?
안타깝게도 저 형변환이 없으면 method reference not expected here라는 컴파일 오류가 발생한다.
다행히 Stream를 Iterable로 중개해주는 메서드를 생성하면 조금 더 편안해진다.
public static <E> Iterable<E> iterableOf(Stream<E> stream) {
return stream::iterator;
}
for(ProcessHandle processHandle : iterableOf(ProcessHandle.allProcesses())) {
// 프로세스 처리
}
❗ iterable만 반환하는 API
이러한 경우에도 Iterable을 Stream으로 중개해주는 메서드를 생성해 사용할 수는 있다.
public static <E> Stream<E> streamOf(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), false);
}
모두를 배려하는 API
API는 한 쪽만 지원하기 보다는 iterable, stream 모두를 배려해서 사용할 수 있게 만들자.
Collection이나 그 하위 타입으로 반환하도록 하자.
❗ Collection을 사용하는 이유
- Iterable의 하위 타입
- stream 메서드 제공
- 👉 반복과 스트림을 동시에 지원
❓ 덩치 큰 시퀀스
- 컬렉션을 반환하기 위해 덩치 큰 시퀀스를 메모리에 올리는건 불필요한 일
- 전용 컬렉션 구현도 고려해보자. (ex: AbstractCollection 상속 받아 직접 구현)
개인적으로는 전용 컬렉션 구현에 부정적인 의견을 갖고 있다.
1. 컬렉션을 직접 구현하다 부가적인 실수를 발생시킬 바에는 전문가들이 잘 만든 것을 사용하는게 낫다.
2. 직접 구현하는 경우 함께 개발하는 다른 개발자가 어떤 식으로 사용해야 하는지 로직을 하나하나 파악해야할 수도 있다.
결론
: 반환 타입으로는 Stream보다 Collection을 이용하자.
참고
- Effective Java - item 47
반응형
'Develop > Java' 카테고리의 다른 글
[Java] 사라진 SQLException (5) | 2022.04.07 |
---|---|
[Java] java.sql.SQLException: Parameter index out of range (0) | 2022.04.04 |
[Java] 인터페이스를 사용하자! (0) | 2022.03.18 |
[Java] Inheritance(상속) vs Composition(조합) (0) | 2022.03.14 |
[Java] 중첩 클래스의 종류 (feat. 멤버 클래스는 static으로!) (0) | 2022.03.14 |