티스토리 뷰
개념
- 스트림에서는 스트림 요소들을 정렬할 수 있는
sorted
라는 메서드를 제공한다.
sorted
메서드는 파라미터에 따라 2가지 버전이 존재한다.
sorted() 메서드
-
스트림 요소의 타입에 따라 기본적으로 제공되는 정렬 방식을 사용한다.
-
Number
나String
같은 경우는 오름차순, 커스텀 클래스의 경우Comparable<T>
로 구현한 방식을 따른다.- 커스텀 클래스의 경우
Comparable<T>
인터페이스를 구현하지 않았을 경우 최종 연산 이후에ClassCastException
이 발생할 수 있다.
- 커스텀 클래스의 경우
-
일반 스트림과 기본형 특화 스트림 모두에 제공되며 기본형 특화 스트림의 경우 해당 primitive 타입에 맞는 정렬 방식이 적용된다.
sorted(Comparator) 메서드
-
스트림 요소들을 함수형 인터페이스
Comparator<? super T> comparator
에서 정의한 방식으로 정렬할 수 있다. -
Comparable<T>
인터페이스를 구현하지 않은 커스텀 클래스는 이 메서드를 사용해서 정렬 방식을 정해주어야ClassCastException
의 발생을 방지할 수 있다.- 기본적으로 정렬 기준이 정해져있는 클래스들의 경우 이 메서드를 사용해서
Comparator<T>
를 정의한다면 기존 정렬 방식을 무시하고 새로운 정렬 방식을 적용할 수 있다. Number
나String
같은 경우는 이 메서드를 사용해서 내림차순으로 정렬할 수 있다.
- 기본적으로 정렬 기준이 정해져있는 클래스들의 경우 이 메서드를 사용해서
-
기본형 특화 스트림의 경우는 이 메서드가 제공되지 않는다.
- 따라서 기본형 특화 스트림의 정렬 기준을 변경하고 싶다면
boxed
메서드를 통해 박싱한 후 이 메서드를 사용해서 정렬을 해야할 것 같다.
- 따라서 기본형 특화 스트림의 정렬 기준을 변경하고 싶다면
예제
-
아래 예제에서 사용되는 내용들은 다양한 상황을 연출하기 위해서 임의로 만들어진 내용이므로 특정 속성에 대해서 왜 저 타입이 사용되었는지 의문을 가지지 말자!
-
예제 코드에서 사용되고 있는 스펙
- Java 15 preview (record라는 새로운 클래스 개념을 사용하기 위해서 해당 프리뷰 버전을 사용. 하위 버전의 경우는 일반 클래스를 생성한 후 getter를 만들고 사용하면 됨) - 참고
- JUnit 5
- Gradle 6.7
기본 데이터 생성
public record Student(int no, String name, int koreanScore, int mathScore, int englishScore) implements Comparable<Student> {
@Override
public int compareTo(Student student) {
int sum = koreanScore + mathScore + englishScore;
int studentSum = student.koreanScore() + student.mathScore() + student.englishScore();
return studentSum - sum;
}
}
private final SortedUsage sortedUsage = new SortedUsage();
private final List<Student> students = List.of(
new Student(1, "hong", 75, 90, 80),
new Student(2, "sujin", 50, 90, 100),
new Student(3, "kate", 90, 75, 75),
new Student(4, "tae", 100, 100, 100),
new Student(5, "lob", 75, 75, 100));
짝수 오름차순으로 정렬하기
Number
나String
같은 자바의 기본 값으로 쓰이는 클래스들을 정렬해보자.
public List<Integer> getEvenNumbersOrderBy(List<Integer> numbers) {
return numbers.stream()
.filter(n -> n % 2 == 0)
.sorted()
.collect(Collectors.toList());
}
- 이런 클래스들은 기본적으로 정렬 방식이 정해져 있다.
- 가볍게
filter
를 사용해서 짝수를 판별하고sorted
를 사용해서Integer
클래스의 기본 정렬 방식(정수의 오름차순)을 사용해서 정렬을 한다.
@Test
@DisplayName("짝수 오름차순으로 정렬하기")
void getEvenNumbersOrderByTest() {
final var numbers = List.of(5, 2, 3, 9, 4);
final var expected = List.of(2, 4);
final var result = sortedUsage.getEvenNumbersOrderBy(numbers);
assertIterableEquals(expected, result);
}
- 테스트가 성공한다.
문자열 내림차순으로 정렬하기
- 이번에는 내림차순으로 정렬해보려고 한다.
public List<String> getStringsOrderByDesc(List<String> strings) {
return strings.stream()
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
}
-
Number
나String
타입의 기본 정렬 방식은 오름차순이다. -
하지만 내림차순이 필요한 경우가 있다.
- 이 경우에
Comparator<T>
를 파라미터로 받는 버전의sorted
메서드를 사용한다. - 여기서는
Collections
클래스에서 제공하는 순서를 뒤집어주는Collections.reverseOrder()
라는 메서드를 사용했다.
- 이 경우에
-
문자열을 내림차순(사전 역순)으로 정렬해보자.
@Test
@DisplayName("문자열 내림차순으로 정렬하기")
void getStringsOrderByDescTest() {
final var strings = List.of("banana", "orange", "apple");
final var expected = List.of("orange", "banana", "apple");
final var result = sortedUsage.getStringsOrderByDesc(strings);
assertIterableEquals(expected, result);
}
- 테스트가 성공한다.
학생들 총점순으로 내림차순 정렬하기
- 이번에는 커스텀으로 만든 클래스를 정렬해 보려고 한다.
public List<Student> getStudentsOrderByDesc(List<Student> students) {
return students.stream()
.sorted()
.collect(Collectors.toList());
}
- 위에서 생성한 기본 데이터 클래스인
Student
클래스는Comparable<Student>
인터페이스를 구현하고 있다. Student
클래스의compareTo
메서드를 보면 학생들의 총점을 구해서 점수가 큰 순으로 비교할 수 있도록 구현되어 있다.- 따라서
Student
클래스의 기본 정렬 방식은 학생들의 총점의 내림차순이다.
@Test
@DisplayName("학생들 총점순으로 내림차순 정렬하기")
void getStudentsOrderByDescTest() {
final var expected = List.of(
new Student(4, "tae", 100, 100, 100),
new Student(5, "lob", 75, 75, 100),
new Student(1, "hong", 75, 90, 80),
new Student(2, "sujin", 50, 90, 100),
new Student(3, "kate", 90, 75, 75));
final var result = sortedUsage.getStudentsOrderByDesc(students);
assertIterableEquals(expected, result);
}
- 테스트가 성공한다.
학생들 수학 점수순으로 내림차순 정렬하기
- 이번에는 위에서 사용한
Student
클래스에서 정렬 방식을 바꿔서 수학 점수의 내림차순으로 정렬하려고 한다.
public List<Student> getStudentsOrderByMathScoreDesc(List<Student> students) {
return students.stream()
.sorted((a, b) -> b.mathScore() - a.mathScore())
.collect(Collectors.toList());
}
-
Student
클래스의 기본 정렬 방식은 총점에 의한 내림차순이지만sorted
메서드 부분을 살펴보면Comparator<T>
를 파라미터로 받는 버전을 사용하고 있는 것을 알 수 있다.- 이로 인해 기본 정렬 방식은 무시되고 내부에 람다로 구현된
Comparator<T>
를 가지고 정렬 작업(수학 점수의 내림차순)을 수행한다.
- 이로 인해 기본 정렬 방식은 무시되고 내부에 람다로 구현된
-
이렇게 클래스가 기본적으로 정렬 방식 정해져 있다고 해도 필요에 따라 메서드나 람다를 활용해서 자유롭게 정렬 방식을 변경할 수 있다.
@Test
@DisplayName("학생들 수학 점수순으로 내림차순 정렬하기")
void getStudentsOrderByMathScoreDescTest() {
final var expected = List.of(
new Student(4, "tae", 100, 100, 100),
new Student(1, "hong", 75, 90, 80),
new Student(2, "sujin", 50, 90, 100),
new Student(3, "kate", 90, 75, 75),
new Student(5, "lob", 75, 75, 100));
final var result = sortedUsage.getStudentsOrderByMathScoreDesc(students);
assertIterableEquals(expected, result);
}
- 테스트가 성공한다.
이상 Stream API에서 사용하는 중간 연산 중 데이터 처리의 기본인 sorted
메서드에 대해 살펴보았다.
'프로그래밍 > Java' 카테고리의 다른 글
[Modern Java] 람다 표현식(Lambda Expression) (3) | 2021.02.16 |
---|---|
[Modern Java] 동작 파라미터화(Behavior Parameterization) (2) | 2021.01.17 |
[Stream API] 중간 연산 - peek 메서드 (0) | 2021.01.07 |
[Stream API] 중간 연산 - flatMap 메서드 (0) | 2021.01.05 |
[Stream API] 중간 연산 - map 메서드 (2) | 2021.01.04 |
- Total
- Today
- Yesterday
- modern java
- 개발자
- jdk14
- #React #ReactJS #리액트
- 충북 콕! 콕!
- flatMapToInt
- flaMap
- 람다
- 회고
- 토이 프로젝트
- #예제 #example #가계부 #Account Book
- 중간 연산
- 계획
- 익명 클래스
- 목표
- Stream API
- Java8
- 스트림
- IntelliJ
- java
- #배열 #array #map 함수
- flatMapToDouble
- import문
- flatMapToLong
- java14
- lambda
- mapToObj
- 다짐
- 변경사항
- 자바
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |