💡 collect() & Collector & Collectors
collect() | 스트림의 최종연산, 매개변수로 매개변수로 Collectors를 필요로 한다. |
Collector | 인터페이스. 컬렉터는 이 인터페이스를 구현해야한다. |
Collectors | 클래스.Collector인터페이스를 구현한 것, 직접 구현할 수 도 있고 미리 작성된걸 사용할 수도 있다. |
// Collecter를 구현한 클래스의 객체를 매개변수로
Object collect(Collector collect)
//Collecter인터페이스를 구현하지 않고 간단히 람다식으로 수집할 때 사용하면 편리함.
Object collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
스트림을 컬렉션과 배열로 변환 - toList(), toSet(), toMap(), toCollection(), toArray()
: 스트림의 요소를 컬렉션에 수집하려면, Collectors의 메서드를 사용하면 되고
List나 Set이 아닌 특정 컬렉션을 지정하려면, toCollection()에 해당컬렉션의 생성자 참조를 매개변수로 넣어주면 된다.
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class StreamEx6 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("이자바", 3, 300),
new Student("김자바", 1, 200),
new Student("안자바", 2, 100),
new Student("박자바", 2, 150),
new Student("소자바", 1, 200),
new Student("나자바", 3, 290),
new Student("감자바", 3, 180),
};
// 학생 이름만 뽑아서 list<String>에 저장
List<String> names = System.of(stuArr).map(Student::getName)
.collect(Collectors.toList());
// 특정 컬렉션 지정하기(arrayList)
ArrayList<String> list = names.stream()
.collect(Collectors.toCollection(ArrayList::new));
// 스트림을 배열로 변환
Student[] stuArr2 = System.of(stuArr).toArray(Student[]::new);
// 매개변수를 지정하지 않은 배열
Object[] stuNames = System.of(stuArr).toArray();
//스트림을 Map<String,Student>로 변환, 학생 이름이 key
Map<String,Student> stuMap = Stream.of(stuArr).collect(Collectors.toMap(s->s.getName(),p->p));
}
}
Class Student implements Comparable<Student>{
String name;
int ban;
int totalScore;
Student(String name ,int ban, int totalScore){
this.name = name;
this.ban = ban;
this.totalScore = totalScore;
}
public String toString(){
return String.format("[%s, %d, %d]", name, ban, totalScore).toString();
}
}
통계 - counting(), summingInt(), averagingInt(), maxBy(), minBy()
: 이미 최종연산에 통계 함수들이 많이 있어서 굳이 collect를 사용할 필요는 없지만,
groupingBy()와 함께 사용될 때 유용한다.
/* 갯수 구하기 Stream.count()와 같다. */
long count = Stream.of(stuArr).collect(counting());
/* 합계 구하기 */
long totalScore = Stream.of(stuArr).collect(summingInt(Student::getTotalScore));
/* max 값 구하기 */
Optional<Student> topStudent = Stream.of(stuArr)
.collect(maxBy(Comparator.comparingInt(Student::getTotalScore)));
/* summingInt와 summarizingInt를 혼동하지 않도록 주의 */
IntSummaryStatistics stat = Stream.of(stuArr)
.collect(summarizingInt(Student::getTotalScore));
리듀싱 - reducing()
: collection으로 리듀싱이 가능하지만, 주의해야할 점은 IntStream등 기본형 스트림에는 매개변수가 3개짜리인 collect()만 정의되어있으므로 매개변수 1개짜리 collect()를 사용하려면 boxed()를 통해 변환해야한다.
IntStream intStream = new Random().ints(1,46).distinct().limit(6);
/* Stream<Integer>로 변환 */
Optional<Integer> max = intStream.boxed().collect(reducing(Integer::max));
/* 변수에 초기값 설정 */
long sum = intStream.boxed().collect(reducing(0 ,(a,b) -> a + b));
/* 변수에 초기값, map, 처리함수 설정 */
int grandTotal = stuStream.collect(reducing(0, Student::getTotalScore,Integer::sum));
문자열 결합 - joining()
: 문자열 스트림의 모든요소를 하나의 문자열로 연결해서 반환한다.
구분자, 접두사, 접미사 지정 가능
스트림의 요소가 문자열이 아닌경우에는 먼저 map()을 이용해서 스트림의 요소를 문자열로 변환해야한다.
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class StreamEx6 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("이자바", 3, 300),
new Student("김자바", 1, 200),
new Student("안자바", 2, 100),
new Student("박자바", 2, 150),
new Student("소자바", 1, 200),
new Student("나자바", 3, 290),
new Student("감자바", 3, 180),
};
String stuNames = Stream.of(stuArr).map(Student::getName)
.collect(joining(",","{","}"));
System.out.println(stuNames);
/* {이자바,김자바,안자바,박자바,소자바,나자바,감자바} */
/* map() 없이 스트림에 바로 joining을 한 것은 스트림요소에 toString을 호출한 결과를 결합한다. */
String studentInfo = Stream.of(stuArr).collect(joining(","));
}
}
Class Student implements Comparable<Student>{
String name;
int ban;
int totalScore;
Student(String name ,int ban, int totalScore){
this.name = name;
this.ban = ban;
this.totalScore = totalScore;
}
public String toString(){
return String.format("[%s, %d, %d]", name, ban, totalScore).toString();
}
}
분할 - partitioningBy()에 의한 분류
: 스트림의 요소를 두 가지, 지정된 조건에 일치하는 그룹과 일치하지 않는 그룹으로 분할할 수 있다.
partitioningBy는 Predicate로 분류한다.
반환형은 Map이다.
1️⃣ 기본 분할
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* Student클래스의 변수 isMale은 성별을 나타낸다. 남자는 true, 여자는 false */
Map<Boolean, List<Student>> stuBySex = stuStream
.collect(partitioningBy(Student::isMale));
List<Student> maleStudent = stuBySex.get(true); // map에서 남학생 목록을 얻는다.
List<Student> femaleStudent = stuBySex.get(false); // map에서 여학생 목록을 얻는다.
2️⃣ 기본분할 + 통계정보
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* Student클래스의 변수 isMale은 성별을 나타낸다. 남자는 true, 여자는 false */
/* 성별 수 */
Map<Boolean, Long> stuNumBySex = stuStream
.collect(partitioningBy(Student::isMale,counting()));
Long mCnt = stuNumBySex.get(true); // 남학생의 수
Long wCnt = stuNumBySex.get(false); // 여학생의 수
/* 성별 1등 */
Map<Boolean, Optional<Student>> topScoreBySex = stuStream
.collect(
partitioningBy(Student::isMale
,maxBy(comparingInt(Student::getScore)))
);
Optional<Student> mTop = topScoreBySex.get(true); // 남학생 1등
Optional<Student> wTop = topScoreBySex.get(false); // 여학생 1등
/* -> 반환형을 클래스(student)로 얻으려면 */
Map<Boolean, Student> topScoreBySex = stuStream
.collect(
partitioningBy(Student::isMale
,collectingAndThen(
maxBy(comparingInt(Student::getScore)),
Optional::get
)
)
);
Student mTop = topScoreBySex.get(true); // 남학생 1등
Student wTop = topScoreBySex.get(false); // 여학생 1등
3️⃣ 이중 분할
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* Student클래스의 변수 isMale은 성별을 나타낸다. 남자는 true, 여자는 false */
/* 성별로 총점이 150 미만인 학생들 */
Map<Boolean, List<Student>> failedStuBySex
= stuStream.collect(
partitioningBy(Student::isMale,
partitioningBy(s -> s.getScore() < 150)
)
);
List<Student> maleStudent = failedStuBySex.get(true).get(true);
List<Student> femaleStudent = failedStuBySex.get(false).get(true);
그룹화 - groupingBy()에 의한 분류
: 스트림의 요소를 특정 기분으로 그룹화시킨다.
groupingBy는 Function으로 분류한다.
반환형은 Map이다.
1️⃣ 기본 그룹화
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* 반별로 학생을 그룹화하기 */
Map<Boolean, List<Student>> stuByBan = stuStream
.collect(groupingBy(Student::getBan));
/*groupingBy()로 그룹화를 하면 기본적으로 List<T>에 담는다
. 그래서 기본적으로 toList()는 생략이 가능하다 .*/
/* 변환하고 싶은 컬렉션을 지정할 수 있다. 메소드가 정의되지않았다면 커스텀이 가능하다. */
Map<Boolean, List<Student>> stuByBan = stuStream
.collect(groupingBy(Student::getBan,toList()));
Map<Boolean, HashSet<Student>> stuByHak = stuStream
.collect(groupingBy(Student::getHak,toCollection(HashSet::new)));
2️⃣ 심화 그룹화
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* 성적의 등급(high, mid, row)으로 그룹화하기 */
Map<Student.Level, Long> stuByLevel = stuStream
.collect(groupingBy(s-> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
},counting())
);
3️⃣ 다수준 그룹화
/* stuStream가 요소가 클래스 Student로 이루어져 있다고 가정한다. */
/* 학년별로 그룹화한뒤 다시 반별로 그룹화하기 */
Map<Integer, Map<Integer, List<Student>>> stuByHakAndBan = stuStream
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan)
));
/* 각 반의 1등 추출하기 */
Map<Integer, Map<Integer, List<Student>>> stuByHakAndBan = stuStream
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan,
collectionAndThen(
maxBy(ComparingInt(Student::getScore)),
Optional::get)
)
));
728x90
반응형
'개발 공부 > Java & Spring' 카테고리의 다른 글
25. 문자기반의 보조스트림 (0) | 2023.04.09 |
---|---|
24. Collector 구현하기 (0) | 2023.03.29 |
22. 스트림의 최종연산 (0) | 2023.03.26 |
21. fork & join 프레임워크 (0) | 2023.03.09 |
20. volatile (0) | 2023.03.09 |