Stream API - 최종 처리
Mathcing
- 최종 처리 단계에서 요소들이 특정 조건에 만족 여부 확인
- true / false 리턴
- allMatch() : 모든 요소가 매개값으로 주어진 Predicate의 조건에 만족하는지
- anyMatch() : 최소 하나의 요소가 매개값으로 주어진 Predicate의 조건에 만족하는지
- nonMatch() : 모든 요소가 매가값으로 주어진 Predicate의 조건에 만족하지 않는지
int[] values = {2, 4, 6};
boolean result = false;
result = Arrays.stream(values)
.allMatch(value -> value % 2 == 0); // 모두 만족
System.out.println(result); // true
result = Arrays.stream(values)
.anyMatch(value -> value % 3 == 0); // 6 하나만 만족
System.out.println(result); // true
result = Arrays.stream(values)
.noneMatch(value -> value % 4 == 0); // 만족하는 값 없음
System.out.println(result); // false
실습 문제
List<Student> list = Arrays.asList(
new Student("이원석", 20, "남자", 100, 100),
new Student("하윤기", 18, "여자", 90, 80),
new Student("이정현", 27, "남자", 80, 70)
);
boolean result = false;
-
20살 이상인 사람이 모두 남자인지 확인
result = list.stream()
.filter(student -> student.getAge() >= 20)
.allMatch(student -> student.getGender().equals("남자"));
System.out.println(result); // true
-
남자 중 평균이 90점 이상인 사람이 한 명 이상인지 확인
result = list.stream()
.filter(student -> student.getGender().equals("남자"))
.anyMatch(student -> ((student.getMath() + student.getEnglish()) / 2) >= 90);
System.out.println(result); // true
Aggregate
- 최종 처리 기능
- 기본 집계 : 요소의 카운팅, 합계, 평균, 최대값, 최소값 등과 같이 하나의 값으로 산출
- count() : 개수 리턴
- findFirst() : 첫번쨰 요소
- max() : 최대 요소
- min() : 최소 요소
- average() : 평균
- sum() : 합계
- 커스텀 집계 : 스트림에서 기본 집계 메서드 제공하지만 다양한 집계 결과물을 만들 수 있도록 reduce() 메서드를 제공
- 매개 타입으로 XXXOperator
- Optional 클래스 : 스트림의 최종 결과 값을 저장하는 객체. 값의 존재 여부 확인, 값이 존재하지 않을 경우 디폴트 값 설정 가능한 각체
- get(): 지정되어 있는 값을 얻을 때 사용
- isPresent() : 값이 저장되어 있는지 확인
- orElse() : get()과 동일하게 저장되어 있는 값을 얻을 때 사용. 값이 저장되어 있지 않을 경우 디폴트 값 설정 가능
- ifPresent(Consumer) : 값이 저장되어 있을 경우 Consumer에서 값을 처리
기본 집계
- 요소의 카운팅, 합계, 평균, 최대값, 최소값 등과 같이 하나의 값으로 산출
- count() : 개수 리턴
- sum() : 합계
- average() : 평균
- max() : 최대 요소
- min() : 최소 요소
- findFirst() : 첫번쨰 요소
count()
// 2의 배수의 개수
long count = Arrays.stream(values)
.filter(value -> value % 2 == 0)
.count();
System.out.println(count); // 출력 결과: 3
count는 long 타입의 자료형을 반환하는 것을 확인.
sum()
// 2의 배수의 합
int sum = Arrays.stream(values)
.filter(value -> value % 2 == 0).sum();
System.out.println(sum); // 출력 결과: 12
average()
// 2의 배수 평균
OptionalDouble average = Arrays.stream(values)
.filter(value -> value % 2 == 0)
.average();
System.out.println(average.getAsDouble()); // optional 사용 시 get을 이용하여 가져오기
// 출력 결과: 4.0
max()
// 2의 배수 중 최대값
OptionalInt max = Arrays.stream(values)
.filter(value -> value % 2 == 0)
.max();
System.out.println(max.getAsInt()); // 출력 결과: 6
min()
// 2의 배수 중 최소값
OptionalInt min = Arrays.stream(values)
.filter(value -> value % 2 == 0)
.min();
System.out.println(min.getAsInt()); // 출력 결과: 2
findFirst()
// 첫번째 요소
OptionalInt findFirst = Arrays.stream(values).filter(value -> value % 2 == 0).
findFirst();
System.out.println(findFirst.getAsInt());
Optional
- 스트림의 최종 결과 값을 저장하는 객체. 값의 존재 여부 확인, 값이 존재하지 않을 경우 디폴트 값 설정 가능한 각체
- get(): 지정되어 있는 값을 얻을 때 사용
- isPresent() : 값이 저장되어 있는지 확인
- orElse() : get()과 동일하게 저장되어 있는 값을 얻을 때 사용. 값이 저장되어 있지 않을 경우 디폴트 값 설정 가능
- ifPresent(Consumer) : 값이 저장되어 있을 경우 Consumer에서 값을 처리
isPresent()
- 값이 저장되어 있는지 확인
// 값이 없는 빈 객체
List<Integer> values = new ArrayList<>();
// values.add(1);
// values.add(4);
OptionalDouble average = values.stream()
.mapToInt(value -> value.intValue()) // 객체를 일반 자료형으로 바꿈
.average();
System.out.println(average); // 출력 결과: OptionalDouble.empty
if(average.isPresent()) {
System.out.println("평균: " + average.getAsDouble());
} else {
System.out.println("데이터가 없음");
}
값의 존재 여부 확인.
값이 없는데 .average()를 실행시킬 경우 에러를 뱉는다. 나눌 수가 없기 때문에.
그럴 때 OptionalDouble을 사용한다. 값이 없을 경우에 에러를 출력하지 않고
OptionalDouble.empty를 출력한다.
위에 add()를 사용하여 값을 넣어줬을 경우에는 평균값을 구해주고
주석으로 가리고 실행시켜볼 경우에는 OptionalDouble.empty가 출력된다.
orElse()
- default값 설정
double avg = values.stream()
.mapToInt(value -> value.intValue())
.average()
.orElse(0.0); // 값이 있을 경우 문제가 없고, 값이 없다면 여기 설정한 값을 defualt 값으로 설정
System.out.println(avg); // 출력 0.0
ifPresent()
- 집계 값을 처리하는 Consumer 등록
List<Integer> values = new ArrayList<>();
values.add(1);
values.add(4);
values.stream()
.mapToInt(value -> value.intValue())
.average()
.ifPresent(d -> System.out.println(d)); // 값이 없을 경우에는 실행되지 않는다.
// 출력 결과: 2.5
// add() 해주지 않을 경우 실행되지 않는다.
커스텀 집계
- 스트림에서 기본 집계 메서드 제공하지만 다양한 집계 결과물을 만들 수 있도록 reduce() 메서드를 제공
- 매개 타입으로 XXXOperator
int[] values = {1, 2, 3, 4, 5, 6};
Arrays.stream(values)
.reduce((left, right) -> left * right) // 집계형
.ifPresent(value -> System.out.println(value));
// 출력 결과: 720
정수형 2개를 입력 받아서 연산을 해준다.
순서대로 1 * 2 = 2. 그다음엔 2 * 2 = 4.
그다음엔 또 4 * 3 = 12. 12 * 4 = 48 … 이런식으로 진행된다.
마찬가지로 값이 없을 경우에는 ifPresent()를 사용했기 때문에 실행되지 않는 것이 확인된다.
Collect
- 필터링 또는 매핑(타입 변환) 후 요소들을 수집하는 최종 처리 메서드인 collect() 제공
- collect() 사용 : 필요한 요소만 새로운 컬렉션으로 리턴 받기 가능
// List 사용
List<Student> students = Arrays.asList(
new Student("이원석", 20, "남자", 100, 100),
new Student("하윤기", 19, "여자", 90, 80),
new Student("이정현", 24, "남자", 80, 70)
);
List<Student> maleList = students.stream()
.filter(student -> student.getGender().equals("남자"))
.collect(Collectors.toList());
maleList.stream()
.map(student -> student.getName())
.forEach(name -> System.out.print(name + " "));
// 출력 결과: 이원석 이정현
남자 이름만 출력.
collect()를 사용하여 수집하고, 수집된 maleList에서 또 새로운 stream을 받아
이름만 출력하도록 했다.
-
// Set 사용
Set<Student> femaleList = students.stream()
.filter(student -> student.getGender().equals("여자"))
.collect(Collectors.toSet());
femaleList.stream()
.map(student -> student.getName())
.forEach(name -> System.out.print(name + " "));
// 출력 결과: 하윤기