프로그래밍/Java
[Stream API] 중간 연산 - distinct 메서드
개발자 카니
2020. 12. 31. 06:22
개념
-
스트림은 고유 요소로 이루어진 스트림을 반환하는 중간 연산인
distinct메서드를 지원한다.- 고유 여부는 객체의
equals와hashCode메서드를 통해 판단한다.
- 고유 여부는 객체의

예제
-
아래 예제에서 사용되는 내용들은 다양한 상황을 연출하기 위해서 임의로 만들어진 내용이므로 특정 속성에 대해서 왜 저 타입이 사용되었는지 의문을 가지지 말자!
-
예제 코드에서 사용되고 있는 스펙
- Java 15 preview (record라는 새로운 클래스 개념을 사용하기 위해서 해당 프리뷰 버전을 사용. 하위 버전의 경우는 일반 클래스를 생성한 후 getter를 만들고 사용하면 됨) - 참고
- JUnit 5
- Gradle 6.7
기본 데이터 생성
public record Song(int no, String title, String albumName, String artist) {
@Override
public boolean equals(Object song) {
return getClass() == song.getClass() && artist.equals(((Song) song).artist);
}
@Override
public int hashCode() {
return artist.hashCode();
}
}
private final DistinctUsage distinctUsage = new DistinctUsage();
private final List<Song> songs = List.of(
new Song(1, "Bohemian Rhapsody", "A Night at the Opera", "Queen"),
new Song(2, "2002", "Speak Your Mind", "Anne-Marie"),
new Song(3, "Blueming", "Love Poem", "IU"),
new Song(4, "Love Poem", "Love Poem", "IU"));
중복 숫자 제거
- 숫자가 담긴 리스트가 주어졌을 때 중복된 숫자를 제거하는 메서드를 만들어보자.
public List<Integer> getDistinctNumbers(List<Integer> lists) {
return lists.stream()
.distinct()
.collect(Collectors.toList());
}
- 테스트
@Test
@DisplayName("중복 숫자 제거")
void getDistinctNumbersTest() {
final var expect = List.of(1, 2, 8, 4);
final var result = distinctUsage.getDistinctNumbers(List.of(1, 2, 2, 8, 4, 1, 4));
assertIterableEquals(expect, result);
}
- 테스트가 가볍게 성공한다.
중복된 가수 이름 제거
- 이번에는 우리가 만든 커스텀 클래스(Song) 를 사용해서 리스트를 만들고 중복을 제거해보자.
public List<Song> getSongsWithDistinctArtist(List<Song> songs) {
return songs.stream()
.distinct()
.collect(Collectors.toList());
}
-
사실 위의 예제와 크게 다른 점은 없다.
-
distinct메서드 자체가 파라미터를 가지고 있지 않기 때문에 오버로딩 정도의 예제다. -
여기서 주의할 점은 커스텀으로 만든 클래스의 경우 Number 타입이나 String 타입과 같은 Java의 기본 데이터 형태를 사용할 때와 다르게
equals와hashCode메서드를 오버라이딩해줘야 한다.- 그렇지 않을 경우
distinct가 정상적으로 작동하지 않는다.
- 그렇지 않을 경우
-
여기서는 가수 이름 을 통해 중복을 제거하도록 테스트해보자.
@Test
@DisplayName("중복된 가수 이름 제거")
void getSongsWithDistinctAlbumNameTest() {
final var result = distinctUsage.getSongsWithDistinctArtist(songs);
result.forEach(System.out::println);
assertEquals(3, result.size());
assertEquals("Bohemian Rhapsody", result.get(0).title());
assertEquals("2002", result.get(1).title());
assertEquals("Blueming", result.get(2).title());
}
- 콘솔에 다음과 같은 실행 결과와 함께 테스트가 성공한다.

-
여기서 Song 클래스의
equals와hashCode메서드를 다음과 같이 오버라이딩했기 때문에 테스트가 정상적으로 성공했다.- 둘 중 하나라도 오버라이딩하지 않았다면
distinct메서드가 정상적으로 작동하지 않아서 테스트가 실패한다.
- 둘 중 하나라도 오버라이딩하지 않았다면

이상 Stream API에서 사용하는 중간 연산 중 distinct 메서드의 간단한 사용법에 대해 살펴보았다.