7. 요소 정렬
▷ 요소를 오름차순 또는 내림차순으로 정렬하는 중간 처리 기능
NO | 리턴 타입 | 메소드(매개변수) | 설명 |
1 | Stream<T> | sorted() | Comparable 요소를 정렬한 새로운 스트림 생성 |
2 | Stream<T> | sorted(Comparator<T>) | 요소를 Comparator에 따라 정렬한 새 스트림 생승 |
3 | DoubleStream | sorted() | double 요소를 올림차순으로 정렬 |
4 | Stream | sorted() | int 요소를 올림차순으로 정렬 |
5 | Stream | sorted() | long 요소를 올림차순으로 정렬 |
◎ Comparable 구현 객체의 정렬
▷ 스트림의 요소가 객체일 경우 객체가 Comparable을 구현하고 있어야만 sorted() 메소드를 사용하여 정렬 가능.
▷ 그렇지 않다면 ClassCastException 발생
1. Student 클래스
public class Student implements Comparable<Student>{ private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public String getName() { return name; } public int getScore() { return score; } @Override public int compareTo(Student o) { return Integer.compare(score, o.score); // score와 o.score가 같을 경우 0, 작으면 음수, 크면 양수 리턴 } }
2. SortingExample 메인 클래스
import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class SortingExample { public static void main(String[] args) { // List 컬렉션 생성 List<Student> studentList = new ArrayList<>(); studentList.add(new Student("홍길동", 30)); studentList.add(new Student("신용권", 10)); studentList.add(new Student("유미선", 20)); // 점수를 기준으로 오름차순으로 정렬한 새 스트림 얻기 studentList.stream() .sorted() .forEach(s -> System.out.println(s.getName() + ": " + s.getScore())); System.out.println(); // 점수를 기준으로 내림차순으로 정렬한 새 스트림 얻기 studentList.stream() .sorted(Comparator.reverseOrder()) .forEach(s -> System.out.println(s.getName() + ": " + s.getScore())); } } // 출력 : // 신용권: 10 // 유미선: 20 // 홍길동: 30 // // 홍길동: 30 // 유미선: 20 // 신용권: 10
◎ Comparator를 이용한 정렬
▷ 요소 객체가 Comparable을 구현하고 있지 않다면, 비교자를 제공하면 요소를 정렬시킬 수 있습니다.
▷ 괄호 안에는 o1이 o2보다 작으면 음수, 같으면 0, 크면 양수를 리턴하도록 작성
▷ o1과 o2가 정수일 경우에는 Integer.compare(o1, o2)를, 실수일 경우에는 Double.compare(o1, o2)를 호출해서 리턴값을 리턴 가능
1. Student 클래스
public class Student { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } public String getName() { return name; } public int getScore() { return score; } }
2. SortingExample 메인 클래스
import java.util.ArrayList; import java.util.List; public class SortingExample { public static void main(String[] args) { // List 컬렉션 생성 List<Student> studentList = new ArrayList<>(); studentList.add(new Student("홍길동", 30)); studentList.add(new Student("신용권", 10)); studentList.add(new Student("유미선", 20)); // 점수를 기준으로 오름차순 정렬 studentList.stream() .sorted((s1, s2) -> Integer.compare(s1.getScore(), s2.getScore())) .forEach(s -> System.out.println(s.getName() + ": " + s.getScore())); System.out.println(); // 점수를 기준으로 내림차순 정렬 studentList.stream() .sorted((s1, s2) -> Integer.compare(s2.getScore(), s1.getScore())) .forEach(s -> System.out.println(s.getName() + ": " + s.getScore())); } } //출력 : //신용권: 10 //유미선: 20 //홍길동: 30 // //홍길동: 30 //유미선: 20 //신용권: 10
Comparable과 Comparator는 둘 다 인터페이스 정렬에 사용되며 객체를 비교할 수 있습니다.
Comparable : compareTo 메소드 구현, 자기 자신과 매개변수 객체를 비교
▷ compareTo(T o)
Comparable : compare 메소드 구현, 두 매개변수 객체를 비교
▷ compare(T o1, T o2)
8. 요소를 하나씩 처리(루핑)
▷ 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것
NO | 리턴 타입 | 메소드(매개변수) | 설명 |
1 | Stream IntStream DoubleStream |
peek(Consumer<? super T> | T 반복 |
2 | peek(IntConsumer action) | int 반복 | |
3 | peek(DoubleConsumer action) | double 반복 | |
4 | void | forEach(Consumer<? super T> action | T 반복 |
5 | forEach(IntConsumer action) | int 반복 | |
6 | forEach(DoubleConsumer action) | double 반복 |
▷ 매개타입인 Consumer는 함수형 인터페이스. 모든 Consumer는 매개값을 처리(소비)하는 accept() 메소드를 가지고 있음.
import java.util.Arrays; public class LoopingExample { public static void main(String[] args) { int[] intArr = {1,2,3,4,5}; // 잘못 작성한 경우 Arrays.stream(intArr) .filter(a -> a%2 == 0) .peek(n -> System.out.println(n)); // peek(중간 처리) 뒤에 sum() 최종처리 - 정상처리 int total = Arrays.stream(intArr) .filter(a -> a%2 == 0) .peek(n -> System.out.println(n)) .sum(); System.out.println("총합: " + total + "\n"); // forEach(최종처리) - 정상처리 Arrays.stream(intArr) .filter(a -> a%2 == 0) .forEach(n -> System.out.println(n)); } } // 출력 : // 2 // 4 // 총합: 6 // // 2 // 4
잘못 작성한 경우는 출력 값이 나오지 않습니다.
peek는 중간에 값을 처리해주는 메소드로 최종 처리가 뒤에 붙지 않으면 동작하지 않습니다.
9. 요소 조건 만족 여부(매칭)
▷ 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능
▷ allMatch(), anyMatch(), noneMatch() 메소드는 매개값으로 주어진 Predicate가 리턴하는 값에 따라 true 또는 false를 리턴
NO | 리턴 타입 | 메소드(매개변수) | 조사 내용 |
1 | boolean | allMatch(Predicate<T> predicate) allMatch(intPredicate predicate) allMatch(LongPredicate predicate) allMatch(DoublePredicate predicate) |
모든 요소가 만족하는지 여부 |
2 | boolean | anyMatch(Predicate<T> predicate) anyMatch(intPredicate predicate) anyMatch(LongPredicate predicate) anyMatch(DoublePredicate predicate) |
최소한 하나의 요소가 만족하는지 여부 |
3 | boolean | noneMatch(Predicate<T> predicate) noneMatch(intPredicate predicate) noneMatch(LongPredicate predicate) noneMatch(DoublePredicate predicate) |
모든 요소가 만족하지 않는지 여부 |
import java.util.Arrays; public class MatchingExample { public static void main(String[] args) { int[] intArr = { 2, 4, 6 }; boolean result = Arrays.stream(intArr) .allMatch(a -> a%2 == 0); System.out.println("모두 2의 배수인가? " + result); result = Arrays.stream(intArr) .anyMatch(a -> a%3 == 0); System.out.println("하나라도 3의 배수가 있는가? " + result); result = Arrays.stream(intArr) .noneMatch(a -> a%3 == 0); System.out.println("3의 배수가 없는가? " + result); } } // 출력 : // 모두 2의 배수인가? true // 하나라도 3의 배수가 있는가? true // 3의 배수가 없는가? false
매칭은 해당 조건을 만족하는 값이 있는지 확인해 true/false로 결과를 받습니다.
10. 요소 기본 집계
▷ 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값 등 하나의 값으로 산출하는 것
◎ 스트림이 제공하는 기본 집계
▷ 스트림은 카운팅, 최대, 최소, 평균, 합계 등을 처리하는 다음과 같은 최종 처리 메소드를 제공
NO | 리턴 타입 | 메소드(매개변수) | 설명 |
1 | long | count() | 요소 개수 |
2 | OptionalXXX | findFirst() | 첫 번째 요소 |
3 | Optional<T> OptionalXXX |
max(Comparator<T>) max() |
최대 요소 |
4 | Optional<T> OptionalXXX |
min(Comparator<T>) min() |
최소 요소 |
5 | OptionalDouble | average() | 요소 평균 |
6 | int, long, double | sum() | 요소 총합 |
import java.util.Arrays; public class AggregateExample { public static void main(String[] args) { // 정수 배열 int arr[] = {1,2,3,4,5}; // 카운팅 long count = Arrays.stream(arr) .filter(n -> n%2 == 0) .count(); System.out.println("2의 배수 개수: " + count); // 총합 long sum = Arrays.stream(arr) .filter(n -> n%2 == 0) .sum(); System.out.println("2의 배수 합: " + sum); // 평균 double avg = Arrays.stream(arr) .filter(n -> n%2 == 0) .average() .getAsDouble(); System.out.println("2의 배수 평균: " + avg); // 최대값 int max = Arrays.stream(arr) .filter(n -> n%2 == 0) .max() .getAsInt(); System.out.println("최대값: " + max); // 최소값 int min = Arrays.stream(arr) .filter(n -> n%2 == 0) .min() .getAsInt(); System.out.println("최소값: " + min); // 첫 번째 요소 int first = Arrays.stream(arr) .filter(n -> n%3 == 0) .findFirst() .getAsInt(); System.out.println("첫 번째 3의 배수: " + first); } } // 출력 : // 2의 배수 개수: 2 // 2의 배수 합: 6 // 2의 배수 평균: 3.0 // 최대값: 4 // 최소값: 2 // 첫 번째 3의 배수: 3
◎ Optional 클래스
▷ Optional, OptionalDouble, OptionalInt, OptionLong 클래스는 단순히 집계값만 저장하는 것이 아니라,
집계값이 없으면 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록
java.util.Optional<T>
→ Optional은 선택형 값을 캡슐화하는 클래스입니다.
→ 값이 있으면 Optional 클래스는 값을 감쌉니다.
→ 값이 없으면 Optional.empty 메소드로 Optional을 반환한다.
NO 기본 타입 래퍼클래스(Wrapper class) 1 byte → Byte 2 short → Short 3 int → Integer 4 long → Long 5 float → Float 6 double → Double 7 char → Character 8 boolean → Boolean
→ 기본 타입의 데이터를 객체로 취급해야 하는 경우 메소드 인수로 객체 타입만이 요구되며,
기본 타입의 데이터를 그대로 사용할 수가 없습니다.
이때 기본 타입의 데이터를 객체로 변환한 후 작업을 수행해야합니다.
◎ Optional 클래스 관련 메소드
NO | 리턴 타입 | 메소드(매개 변수) | 설명 |
1 | boolean | isPresent() | 집계값이 있는지 여부 |
2 | T double int long |
orElse(T) orElse(double) orElse(int) orElse(long) |
집계값이 없을 경우 디폴트 값 설명 |
3 | void | ifPresent(Consumer) ifPresent(DoubleConsumer) ifPresent(IntConsumer) ifPresent(LongConsumer) |
집계값이 있을 경우 Consumer에서 처리 |
◎ 최종 처리에서 average 사용시 요소 없는 경우를 대비하는 방법
1) isPresent() 메소드가 true를 리턴할 때만 집계값을 얻는다.
OptionalDouble optional = stream.average(); if(optional.isPresent()){ System.out.println("평균: " + optional.getAsDouble()); } else { System.out.println("평균 : 0.0"); }
2) orElse() 메소드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다.
double avg = stream.average() .orElse(0.0); System.out.println("평균: " + avg);
3) ifPresent() 메소드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다.
stream.average() .ifPresent(a -> System.out.println("평균: " + a));
sorted, 루핑, 매칭, optional 등을 이용해서 정렬, 집계 등을 이용할 수 있습니다.
아직 끝나지 않아서 다음 글에서 또 정리할게요~!!
많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

'BackEnd > Java' 카테고리의 다른 글
[java] 이것이 자바다 ch18 데이터 입출력 1 (Writer, Reader) (0) | 2023.01.30 |
---|---|
[java] 이것이 자바다 ch17 스트림(reduce, 병렬) (0) | 2023.01.30 |
[백준 문제 10250번] ACM 호텔 문제 (0) | 2023.01.29 |
[java] 이것이 자바다 ch17 스트림(필터링, 매핑, wrapper) (0) | 2023.01.28 |
[java] 이것이 자바다 ch17 스트림(내부 반복자, 파이프라인, 인터페이스) (2) | 2023.01.27 |