새롭게 알게된 Stream의 Collectors 기능을 적어보겠습니다.
List<Integer> numbers = List.of(1, 2, 3, 1);
위의 numbers 변수를 통해 다양한 기능을 학습해보겠습니다.
@Test
void toList() {
List<String> result = numbers.stream()
.map(String::valueOf)
.collect(Collectors.toList());
assertThat(result).containsExactly("1", "2", "3", "1");
}
가장 기본적인 형태입니다.
각각의 숫자들을 String
으로 변환하여 변환된 값들을 List<String>
으로 반환해줍니다.
만약 구체적인 클래스인 LinkedList
로 반환받고 싶으면 어떻게 해야될까요??
이때는 toCollection() 메서드를 사용하면 됩니다.
코드를 통해 보겠습니다.
@Test
void toCollection() {
LinkedList<String> result = numbers.stream()
.map(String::valueOf)
.collect(Collectors.toCollection(LinkedList::new));
assertThat(result).containsExactly("1", "2", "3", "1");
}
toCollection(LinkedList::new)
를 통해 LinkedList로 반환받을 수 있었습니다.
또한 불변 List로 반환받을 수 있습니다.
List<Integer> result = numbers.stream()
.collect(Collectors.toUnmodifiableList());
당연히 불변이기 때문에 반환된 List의 내부 값을 변경하려고 하면 예외가 발생합니다.
@Test
void toUnmodifiableList() {
List<Integer> result = numbers.stream()
.collect(Collectors.toUnmodifiableList());
assertThatThrownBy(() -> result.add(10))
.isInstanceOf(UnsupportedOperationException.class);
}
Set
으로 바꾸기 위한 방법 또한 List
와 유사합니다.
- Collectors.toSet()
- Collectors.toCollection(LinkedHashSet::new)
- Collectors.toUnmodifiableSet()
마지막의 List대신 Set을 붙여준다는 차이만 있기 때문에, 예시 코드만 첨부하겠습니다.
@Test
void toSet() {
Set<Integer> result = numbers.stream()
.collect(Collectors.toSet());
assertThat(result).containsExactly(1, 2, 3);
}
@Test
void toCollection() {
LinkedHashSet<Integer> result = numbers.stream()
.collect(Collectors.toCollection(LinkedHashSet::new));
assertThat(result).containsExactly(1, 2, 3);
}
@Test
void toUnmodifiableSet() {
Set<Integer> result = numbers.stream()
.collect(Collectors.toUnmodifiableSet());
assertThatThrownBy(() -> result.add(4))
.isInstanceOf(UnsupportedOperationException.class);
}
이번에 새로 알게 된 기능 중 굉장히 유용하게 사용할 수 있을 거 같은 것 중 하나입니다.
collecting을 먼저 진행한 결과를 통해 새로운 값을 만들 수 있음!!
이해하기 쉽게 예제 클래스를 제가 만들어보았습니다.
class Score {
private final List<Integer> numbers;
public Score(List<Integer> numbers) {
this.numbers = numbers;
}
public List<Integer> getNumbers() {
return numbers;
}
}
다음과 같이 List<Integer>를 통해 생성할 수 있는 Score 객체가 있다고 과정해봅시다.
@Test
void collectingAndThen() {
List<String> source = List.of("1", "2", "3", "4");
Score score = source.stream()
.map(Integer::parseInt)
.collect(Collectors.collectingAndThen(Collectors.toList(), Score::new));
//변환된 값들을 List로 만들고, 이 값을 통해 Score 객체를 생성한다.
assertThat(score.getNumbers()).containsExactly(1, 2, 3, 4);
}
그럼 다음과 같이 변환된 값들을 List로 만들고, 이 값을 통해 Score 객체를 생성할 수 있습니다.
굉장히 유용하다 생각이 들었고, 여러 곳에서 적용하여 사용해보자 생각이 들었습니다.
아직도 모르는 기능이 많고, 얼른 배우고 싶다는 생각이 가득해지는 것 같습니다.
꾸준히 성장하는 개발자가 되길~~