본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch17 스트림(sorted, 루핑, 매칭, optional)

728x90

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 등을 이용해서 정렬, 집계 등을 이용할 수 있습니다.

 

아직 끝나지 않아서 다음 글에서 또 정리할게요~!!

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

728x90