스트림 클래스는 최종 처리 단계에서 요소들이 특정 조건에 만족하는지 조사할 수 있도록 세 가지 매칭 메소드를 제공하고 있다.
allMatch()
: 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하는지 조사anyMatch()
: 최소한 한 개의 요소가 매개값으로 주어진 Predicate의 조건을 만족하는지 조사noneMatch()
: 모든 요소들이 매개값으로 주어진 Predicate의 조건을 만족하지 않는지 조사
int[]
배열로부터 스트림을 생성한 뒤
import java.util.Arrays;
public class MatchExample {
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
집계(Aggregate)는 최종 처리 기능으로 요소들을 처리해서
카운팅, 합계, 평균값, 최댓값, 최솟값 등과 같이 하나의 값으로 산출하는 것을 말한다.
스트림은 다음과 같이 기본 집계 메소드를 제공하고 있다.
OptionalXXX
는
Optional
, OptionalDouble
, OptionalInt
, OptionalLong
클래스 타입을 말한다.값 기반 클래스(value-based class)
이다.get()
, getAsDouble()
, getAsInt()
, getAsLong()
을 호출하면 된다.import java.util.Arrays;
public class AggregateExample {
public static void main(String[] args) {
long count = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 2 == 0)
.count();
System.out.println("2의 배수 개수: " + count);
long sum = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 2 == 0)
.sum();
System.out.println("2의 배수의 합: " + sum);
double avg = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 2 == 0)
.average()
.getAsDouble();
System.out.println("2의 배수의 평균: " + avg);
int max = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 2 == 0)
.max()
.getAsInt();
System.out.println("2의 배수 중 최댓값: " + max);
int min = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 2 == 0)
.min()
.getAsInt();
System.out.println("2의 배수 중 최솟값: " + min);
int first = Arrays.stream(new int[]{1, 2, 3, 4, 5})
.filter(n -> n % 3 == 0)
.findFirst()
.getAsInt();
System.out.println("첫 번째 3의 배수: " + first);
}
}
2의 배수 개수: 2
2의 배수의 합: 6
2의 배수의 평균: 3.0
2의 배수 중 최댓값: 4
2의 배수 중 최솟값: 2
첫 번째 3의 배수: 3
Optional
,OptionalDouble
,OptionalInt
,OptionalLong
클래스들은 저장하는 값의 타입만 다를 뿐 제공하는 기능은 거의 동일하다.
Optional 클래스는 단순히 집계 값만 저장하는 것이 아니라,
컬렉션의 요소는 동적으로 추가되는 경우가 많다.
만약 아래 코드와 같이 컬렉션의 요소가 추가되지 않아 저장된 요소가 없을 경우,
List<Integer> list = new ArrayList<>();
double avg = list.stream()
.mapToInt(Integer :: intValue)
.average()
.getAsDouble();
System.out.println("평균: " + avg);
(요소가 없으므로) 당연히 평균값도 없기 때문에 NoSuchElementException
예외가 발생한다.
NoSuchElementException
예외가 발생하는 상황을 방지하기 위해 세 가지 방법을 사용할 수 있다.
1. Optional 객체를 얻어 isPresent()
메소드로 평균값 여부를 확인하기
OptionalDouble optional = list.stream()
.mapToInt(Integer :: intValue)
.average();
if (optional.isPresent()) {
System.out.println("평균: " + optional.getAsDouble());
} else {
System.out.println("평균: 0.0");
}
2. orElse() 메소드로 디폴트 값 정해놓기
double avg = list.stream()
.mapToInt(Integer::intValue)
.average()
.orElse(0.0);
System.out.println("평균: " + avg);
3. ifPresent() 메소드로 평균값이 있을 경우에만 값을 이용하는 람다식 실행하기
list.stream()
.mapToInt(Integer::intValue)
.average()
.ifPresent(a -> System.out.println("평균: " + a));
전체 코드
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
public class OptionalExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
/**
* 예외 발생 (java.util.NoSuchElementException
double avg = list.stream()
.mapToInt(Integer :: intValue)
.average()
.getAsDouble();
*/
//방법 1
OptionalDouble optional = list.stream()
.mapToInt(Integer :: intValue)
.average();
if (optional.isPresent()) {
System.out.println("방법1_평균: " + optional.getAsDouble());
} else {
System.out.println("방법1_평균: 0.0");
}
//방법 2
double avg = list.stream()
.mapToInt(Integer::intValue)
.average()
.orElse(0.0);
System.out.println("방법2_평균: " + avg);
//방법3
list.stream()
.mapToInt(Integer::intValue)
.average()
.ifPresent(a -> System.out.println("방법3_평균: " + a));
}
}
방법1_평균: 0.0
방법2_평균: 0.0
스트림은 기본 집계 메소드인 sum(), average(), count(), max(), min()을 제공하지만,
프로그램화해서 다양한 집계 결과물을 만들 수 있도록 reduce() 메소드도 제공한다.
XXXOperator 매개값은 집계 처리를 위한 람다식을 대입한다.
예를 들어 학생들의 총점은 학생 스트림에서 점수 스트림으로 매핑해서 다음과 같이 얻을 수 있다.
int sum = studentList.stream()
.map(Student::getScore)
.reduce((a, b) -> a + b)
.get();
위의 코드는 스트림에 요소가 없을 경우 NoSuchElementException
이 발생하지만,
아래의 코드는 디폴트 값인 0을 리턴한다.
int sum = studentList.stream()
.map(Student :: getScore)
.reduce(0, (a, b) -> a + b);
스트림에 요소가 있을 경우에는 두 코드 모두 동일한 결과를 산출한다.
import java.util.Arrays;
import java.util.List;
public class ReductionExample {
public static void main(String[] args) {
List<Student> studentList = Arrays.asList(
new Student("김", 92),
new Student("이", 95),
new Student("박", 88)
);
//sum 이용
int sum1 = studentList.stream()
.mapToInt(Student :: getScore)
.sum();
//reduce(BinaryOperator<Integer> ac) 이용
int sum2 = studentList.stream()
.map(Student::getScore)
.reduce((a, b) -> a + b)
.get();
//reduce(int identity, IntBinaryOperator op) 이용
int sum3 = studentList.stream()
.map(Student :: getScore)
.reduce(0, (a, b) -> a + b);
System.out.println("sum1: " + sum1);
System.out.println("sum2: " + sum2);
System.out.println("sum3: " + sum3);
}
}
sum1: 275
sum2: 275
sum3: 275
이것이 자바다 책