자바 7까지 원소를 반환하는 메서드의 반환 타입으로 가장 적합한 타입은 컬렉션 인터페이스였지만 자바 8이 스트림이라는 개념을 들고 오면서 이 선택이 복잡한 일이 되어 버렸다.
어댑터 메서드
- 스트림은 반복을 지원하지 않는다. 따라서 API를 스트림만 반환하도록 짜놓으면 반환된 스트림을 for-each로 반복하길 원할 때 불편할 것이다.
- 사실 Stream 인터페이스는 Iterable 인터페이스가 정의한 추상 메서드를 전부 포함하고 정의한 방식대로 동작하지만 Stream이 Iterable을 확장하지 않았기 때문에 이를 사용할 수 없다.
형변환을 통한 우회 방법
- Stream의 iterator 메서드에 메서드 참조를 건내고 적절히 형변환 하면 동작하긴 하지만 너무 난잡하고 직관성이 떨어진다.
어댑터 메서드를 사용
- 자바의 타입 추론이 문맥을 잘 파악하여 어댑터 메서드 안에서 따로 형변환 하지 않아도 된다.
- 어댑터를 사용하면 어떤 스트림도 for-each 문으로 반복할 수 있다.
어댑터 활용
- 스트림에서 파일을 읽을 때 Files.lines 메서드를 사용하는데 파일을 읽는 동안 발생하는 모든 예외를 알아서 처리해 준다.
- 따라서 반복 버전에서도 Files.lines를 사용하면 좋다. 위처럼 어댑터를 사용하면 반복문으로 쓸 수 있다.
- 반대로 API가 Iterable만 반환했을 때 이를 스트림에서 처리하려면 아래와 같이 Iterable을 Stream으로 중개하는 어댑터 메서드를 사용하자.
객체 시퀀스를 반환하는 메서드를 작성할 때 해당 메서드가 스트림 파이프라인 또는 반복문에서만 쓰일걸 안다면 그에 맞게 반환하도록 작성해 주자.
하지만 공개 API를 작성할 때는 스트림 파이프라인과 반복문을 사용하는 사람 모두를 배려해야 한다.
Collection 인터페이스는 Iterable 하위 타입이고 stream 메서드도 제공하니 반복과 스트림을 동시에 지원한다.
따라서 원소 시퀀스를 반환하는 공개 API 반환 타입에는 Collection이나 그 하위 타입을 쓰는게 일반적으로 최선 이다.
전용 컬렉션
단지 컬렉션을 반환한다는 이유로 덩치 큰 시퀀스를 메모리에 올려서는 안 된다.
반환할 시퀀스가 크지만 표현을 간결하게 할 수 있다면 전용 컬렉션을 구현하는 방안을 검토해 보자.
- 주어진 집합의 멱집합을 반환할 때, 원소 개수가 n개이면 멱집합의 원소 개수는 2^n개가 된다.
- 그러니 멱집합을 표준 컬렉션 구현체에 저장하는 것은 위험하다.
- AbstractList를 이용하여 전용 컬렉션을 손쉽게 구현할 수 있다.
- 멱집합을 구성하는 각 원소의 인덱스를 비트 벡터로 사용하는 것이다.
- 인덱스의 n번째 비트 값은 멱집합의 해당 원소가 원래 집합의 n번째 원소를 포함하는지 여부를 알려준다.
AbstractCollection을 활용해서 Collection 구현체를 작성할 때는 Iterable용 메서드 외에 contains와 size만 더 구현하면 된다.
만약 이 2가지를 구현하는 게 불가능하다면 컬렉션보다는 스트림이나 Iterable을 반환하자.
결론
- 원소 시퀀스를 반환하는 메서드를 작성할 때 컬렉션을 반환할 수 있다면 그렇게 하자.
- 반환 전부터 이미 원소들을 컬렉션에 담아 관리하고 있거나 컬렉션을 하나 더 만들어도 될 정도로 원소 개수가 적다면 ArrayList 같은 표준 컬렉션에 담아 반환하자.
- 그렇지 않다면 전용 컬렉션을 구현할지 고민하고, 그게 불가능하다면 스트림과 Iterable 중 더 자연스러운 것을 반환하자.
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] Item 49. 매개변수가 유효한지 검사하라 (0) | 2023.07.16 |
---|---|
[Effective Java] Item 48. 스트림 병렬화는 주의해서 사용하라 (0) | 2023.07.09 |
[Effective Java] Item 46. 스트림에서는 부작용 없는 함수를 사용하라 (1) | 2023.07.09 |
[Effective Java] Item 45. 스트림은 주의해서 사용하라 (0) | 2023.07.08 |
[Effective Java] Item 44. 표준 함수형 인터페이스를 사용하라 (0) | 2023.07.08 |