컬렉션,배열,파일,디렉토리 --> 오리지널 스트림 --> 중간 처리(중간 스트림) --> 최종 처리 --> 결과
- 스트림은 데이터를 읽기만 할 뿐 변경시키지 않음
- 일회용 such as Iterator
- 작업을 내부 반복으로 처리함 cf) 외부 반복자 : Iterator
오리지널 스트림 ex) student.stream();
● 중간 처리 : 필터링, 매핑(변환), 정렬, 그룹핑, 루핑(순환)
- 메소드 : 리턴타입이 스트림
① 필터링 : distinct(), filter()
- 지네릭이 바뀌지 않음
② 매핑 : map__(), flatMap__()
- 지네릭이 바뀜 ex) <Student> -> <String>(Student.getName())
- map : 하나의 요소를 단일 스트림의 요소를 매핑(1 -> 1)
- flatMap : 스트림이 배열일 경우 모든 요소(여러개의 요소)를 단일 스트림의 요소로 매핑(여러개 -> 1)
③ 정렬 : sorted()
- Comparable을 구현 한 클래스에서만 사용 가능, Comparable이 구현되지 않은 클래스는 예외 발생
- Comparator로 지정 가능, 지정하지 않을 시 기본 정렬 기준(Comparable) 사용
④ 루핑 : peek()
● 최종 처리 : 매칭, 집계(합계, 평균, 카운팅, 최대값, 최소값), 수집, 루핑
- 리덕션 : 대량의 데이터를 가공해서 축소하는 것 ex) 합계, 평균, 카운팅, 최대값, 최소값
- 메소드 : 리턴타입이 기본 타입 or Optional___
→Optional__ : 타입이 래퍼 클래스임(언박싱이 필요함)
① 매칭 : __Match();
- 요소들이 조건에 만족하는지 확인
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); // true
result = Arrays.stream(intArr).anyMatch(a -> a%3 == 0);
System.out.println("하나라도 3의 배수인가 ? " + result); // true
result = Arrays.stream(intArr).noneMatch(a -> a%3 == 0);
System.out.println("3의 배수는 없는가 ? " + result); // false
}
② 집계 : sum(), average(), count(), max(), min(),
커스텀합계(reduce()) : 요소를 하나씩 줄여가며 계산
③ 수집 : collect()
- 주로 요소를 그룹화하거나 분활한 결과를 컬렉션에 담아 반환할 때 사용, 매개변수로 Collector를 받음
- Collectors.toList(), toSet(), toMap(key, value), toCollection(), toArray() : 스트림->컬렉션 or 배열
- groupingBy(Function) / partitioningBy(Predicate) : 스트림 ->Map
groupingBy(key, value) & partitioningBy(key, value) 라고 생각
// 1. 단순분할(성별)
Map<Boolean, List<Student2>> stuBySex = Stream.of(stuArr)
.collect(Collectors.partitioningBy(Student2::isMale));
List<Student2> maleStudent = stuBySex.get(true);
List<Student2> femaleStudent = stuBySex.get(false);
// 2. 단순분할 + 통계(성별 학생수)
Map<Boolean, Long> stuNumBySex = Stream.of(stuArr)
.collect(Collectors.partitioningBy(Student2::isMale, Collectors.counting()));
System.out.println("남학생 수 : " + stuNumBySex.get(true));
System.out.println("여학생 수 : " + stuNumBySex.get(false));
// 3. 단순분할 + 통계(성별 1등)
Map<Boolean, Optional<Student2>> topScoreBySex = Stream.of(stuArr)
.collect(Collectors.partitioningBy(Student2::isMale, Collectors.maxBy(Comparator.comparingInt(Student2::getScore))));
System.out.println("남학생 수 : " + topScoreBySex.get(true));
System.out.println("여학생 수 : " + topScoreBySex.get(false));
// 4. 다중분할(성별, 불합격자)
Map<Boolean, Map<Boolean, List<Student2>>> failedStuBySex = Stream.of(stuArr)
.collect(Collectors.partitioningBy(Student2::isMale, Collectors.partitioningBy(s -> s.getScore() <= 100)));
List<Student2> failedMaleStu = failedStuBySex.get(true).get(true); // 1번get: 성별, 2번get: score<=100
List<Student2> failedFemaleStu = failedStuBySex.get(false).get(true);
○ collect(supplier, accumulator, combiner) 구현
- supplier - Supplier<R> : 사용자정의 컨테이너 생성
- accumulator - BiConsumer<R, ? super T> : 스트림의 요소를 수집
- combiner - BiConsumer<R, R> : 병렬 스트림의 경우 두 컨테이너를 병합
④ 루핑 : forEach()
double avg = list.stream() // 오리지널 스트림 (Collections -> Stream)
.mapToInt(s -> s.getScore()) // 중간 처리 (Stream -> IntStream)
.average() // 최종 처리 (IntStream -> OptionalDouble)
.getAsDouble(); // 언박싱(Wrapper -> 기본(OptionalDouble -> double))
System.out.println("평균 점수 : " + avg);
○ 병렬 처리 : parallelStream()
- 내부적으로 쓰레드를 사용해서 병렬로 처리함
● 스트림의 변환
스트림→기본형 스트림 | Stream→IntStream | mapToInt(Function) | |
기본형 스트림→스트림 |
IntStream→Stream | boxed() | |
기본형 스트림→기본형 스트림 | IntStream→DoubleStream | asDoubleStream() | |
2개 스트림→스트림 | Stream, Stream → Stream | concat(Stream a, Stream b) | |
스트림의 스트림→스트림 | Stream<Stream>→Stream | flatMapTo__(Function) | |
스트림↔병렬스트림 | parallel() : 스트림→병렬스트림 sequential() : 스트림←병렬스트림 |
||
스트림→컬렉션(List,Set) | Stream→Collection,List,Set | collect(Collectors.to___()) | |
컬렉션→스트림 | Collection,List,Set→Stream | stream() | |
스트림→컬렉션(Map) | Stream→Map | collect(Collectors.toMap(function)) | |
스트림→배열 | Stream->Object[] | toArray() |