간단한 Stream 사용서
스트림 만들기
객체 배열로부터 스트림을 만드는 방법
-
of() 사용하기 ```java - Stream
Stream.of(T...values)// 가변인자 - Stream strStream = Stream.of("a","b","c"); //가변인자 - Stream Stream.of(T[]) - Stream strStream = Stream.of(new String[]{"a","b","c"}); - Arrays.stream(T[]) 사용하기
- Stream
Arrays.stream(T[]) - Stream
strStream = Arrays.stream(new String[]{"a","b","c"});
- Stream
- Stream
Arrays.stream(T[] array, int startInclusive, int endInclusive)// 배열 일부만 스트림으로 - Stream
strStream = Arrays.stream(new String[]{"a","b","c", 0 , 3); //0~2인덱스
- Stream
- Stream
- Arrays.stream(T[]) 사용하기
- Stream 타입이 아닌 IntStream처럼 기본형 타입의 스트림으로 타입을 설정할 수도 있다. ```
스트림 객체 생성 예시
List<Integer> list = Arrays.asList(1,2,3,4,5);
Stream<Integer> intStream = list.strem();// list를 stream으로
intStream.forEach(System.out::print);
//stream은 1회용. stream에 대해 최종연산을 수행하면 해당 stream은 닫힌다.(재사용 불가)
intStream= list.stream();
intStream.forEach(System.out::print);
String[] strArr = {"a","b","c"};
Stream<String> strStream = Stream.of(strArr);
Stream<String> strStream = Arrays.stream(strArr);
strStream.forEach(System.out::print);
int[] intArr = {1,2,3,4};
IntStream intStream = Arrays.stream(intArr);
IntStream.forEach(System.out::print);
Integer[] intArr = {1,2,3,4};// 기본형 1234이지만 알아서 오토박싱되어 Integer타입으로 변환된다.
Stream<Integer> intStream = Arrays.stream(intArr);
IntStream.forEach(System.out::print);
스트림으로 임의의 난수 만들기
IntStreamintStream = new Random().ints();// 무한 스트림
intStream.limit(5).forEach(System.out::println);//5개의 요소만 출력한다.
IntSteram intStream = new Random().ints(5)//크기가 5인 난수 스트림을 반환
Integer.MIN_VALUE <= ints() <= Integer.MAX_VALUE
Long.MIN_VALUE <= longs() <= Long .MAX_VALUE
0.0 <= doubles() < 1.0
- 난수를 요소로 갖는 스트림 생성 (ints()등) * 지정한 범위의 난수를 요소로 갖는 스트림을 생성하는 메서드(Random클래스)
스트림으로 특정 범위의 정수 만들기
IntStream intStream.range(int begin, int end)
IntStream IntSteram.rangeClosed(int begin, int end)
-------------------------------------------------
IntStream intStream = IntStream.range(1,5);//1,2,3,4
IntStream intStream = IntStream.rangeClosed(1,5);//1,2,3,4,5
람다식을 통한 스트림 생성(iterate(), generate())
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)// 이전 요소에 독립적
static <T> Stream<T> generate(Supplier<T> s)// 이전 요소에 독립적
- T seed는 초기값을 의미한다.
- 예로 Stream.iterate(0, n->n+2)일 경우, iteratre()는 0,2,4,6,8,….의 2씩 증가하는 값을 무한히 내보내게 된다.
- iterate()는 주어진 seed 값을 기반으로 람다식을 호출하고 람다식의 리턴값이 다시 seed로 초기화되어 계속 이어지는 무한 스트림을 생성하는 메서드인 것이다.
- gnerate() 또한 무한 스트림을 만드는 메서드이다. iterate()와의 차이점은 처음에 주어지는 seed 값이 없다는 점. 따라서 매개변수로 오는 람다식은 seed 값이 필요없는 Supplier 타입의 함수 인터페이스 형식이어야 한다.
Stream<Double> randomStream = Stream.generate(Math:: random) Stream<Integer> oneStream =Stream.generate(() -> 1 );
- 예제를 보고 이해도를 높여보자
Stream<Integer> intStream =Stream.iterate(0, n->n+2); intStream.limit(10).forEach(System.out::println);//limit()을 통해 무한 스트림의 결과값의 개수를 제한한다. Stream<Integer> oneStream =Stream.generate(() -> 1 ); oneStream.limit(10).forEach(System.out::println);
파일과 빈을 스트림으로 만들기
파일을 source로 한 스트림 생성
Stream<Path> Files.list(Path.dir)// path는 파일 혹은 디렉토리를 의미
Stream<String> Files.lines(path path); // lines()파일의 내용을 라인별로 스트림하는 메서드이다.
Stream<String> Files.lines(path path, Charset cs);
Stream<String> lines() //BufferedReader 클래스의 메서드
빈(empty) 스트림 생성
Stream emptyStream = Stream.empty();// 빈 스트림을 생성해 반환한다. long count =emptyStream.count();// count()의 반환값은 0이다.
스트림의 연산
중간연산과 최종연산
- 중간 연산 : 연산결과가 스트림인 연산, 반복적으로 적용 가능하다.
- 최종연산 : 연산결과가 스트림이 아닌 연산. 단 한번만 적용가능(스트림의 요소를 소모)
stream.distinct().limit(5).sorted().forEach.System.out::println)
중간 연산의 종류
| 중간 연산 | 설명 |
|——–|——–|
| distinct() | 중복 제거 |
| Stream
최종 연산의 종류
| 최종연산 | 설명 |
|—|—|
| void forEach(Consumer<’?’ super T > action) | 각 요소에 지정된 작업 수행 |
| void forEachOrdered(Consumer<’?’ super T > action) | |
| long count() | 스트림의 요소의 개수를 반환 |
| Optional<T> max(Comparator< '?' super T> comparator) | 스트림의 최대값 반환 |
| Optional<T> max(Comparator< '?' super T> comparator) | 스트림의 최소값 반환 |
| Optional<T> findAny() // 아무거나 하나 | 스트림 요소 하나를 반환 |
| boolean allMatch(Predicate<T> p) //모두 만족하는지 | 주어진 조건을 모든 요소가 만지, 만족시키지 않는지 확인 |
| boolean anyMatch(Predicate<T> p) //하나라도 만족하는지 |
|
| boolean noneMatch(Predicate
중간연산 살펴보기
- skip(), limit()
- Stream
skip(long n): 앞에서부터 n개 요소 건너뛰기(삭제하는 것이 아님. 건너뛰기) - Stream
limit(long maxSize): maxSize 이후의 요소는 잘라냄. IntStream inStream = IntSteam.rangeClosed(1, 10); //12345678910 intStream.skip(3).limit(5).forEacj(system.out::print); //45678
- Stream
- filter(), distinct()
- Stream
filter(Predicate prediacate : 조건에 맞지 않는 요소 제거 - Stream
distinct() : 중복제거 IntStream inStream = IntSteam.of(1,2,2,3,3,3,4,5,5,5) intStream.dstinct().forEach(System.out::print);//1,2,3,4,5 IntStream inStream = IntSteam.rangeClosed(1, 10); //12345678910 intStream.filter(i-> i%2==0).forEach(System.out::print);//2,4,6,8,10 intStream.filter(i->i%2!==0 && i%3!=0).forEach(System.out::print);//두 조건식을 &&을 사용할 수도 있고 filter()를 연속으로 사용할 수도 있다. intStream.filter(i->i%2!==0).filter(i-> i%3!=0).forEach(System.out::print);
- Stream
- sorted()
- Stream
sorted() : 스트림의 요소를 기본정렬(Comparable)로 정렬 - Stream
sorted(Comparator comparator): 지정된 Comparator로 정렬 //CCaaabccdd 기본적으로 대문자가 먼저오고 소문자가 온다. strStream.sorted(); strStream.sorted(Comparator.naturalOrder()); strStream.sorted((s1,s2) -> s1.compareTo(s2)); strStream.sorted(String:compareTo); //ddccbaaaCC 위의 순서를 거꾸로 하여 소문자(내림차순)- 대문자(내림차순) strStream.sorted(Comparator.reverseOrder()); strStream.sorted(Comparator.<Sting>naturalOrder().reversed()) //aaabCCccdd String 클래스에 static으로 선언되어 있는 Enum을 선택하여 편하게 정렬할 수 있다. strStream.sorted(String.CASE_INSENSITIVE_ORDER.reversed()) //ddCCccbaaa strStream.sorted(String.CASE_INSENSITIVE_ORDER.reversed()) //bddCCccaaa// 알파벳 순서 상관없이 연속한 글자의 개수대로 나온다. strStream.sorted(Comparator.comparing(String::length)) strStream.sorted(Comparator.comparingInt(String::length)) //aaaddCCccb strStream.sorted(Comparator.comparing(String::length).reversed())
3-1. Comparator의 comparing()으로 정렬 기준을 제공 - comparing(Function<T, U> keyExtractor) - comparing(Function<T, U> keyExtractor, Comparator keyComparator) - comparing은 Comparator 타입으로 반환한다. ```java studentStream.sorted(Comparator.comparing(Student::getBan)) //반별로 정렬 .forEach(System.out::println); ``` - 정렬 기준이 여러개일 경우, thenComparing()을 사용한다.(연속 사용가능) - thenComparing(Comparator
other) thenComparing(Function<T, U> keyExtractor) thenComparing(Function<T, U> keyExtractor, Comparator keyComp) ```java studentStream.sorted(Comparator.comparing(Student::getBan) //반별로 정리 .thenComparing(Student::getTotalScore) // 총점별로 정렬 .thenComparing(Student::getName)) // 이름별로 정렬 .forEach(System.out::println); ``` - Stream
- map()
- 스트림의 요소를 변화시켜 다른 타입 혹은 다른 값의 스트림으로 반환한다.
- Stream
map(Function<T, R> mapper) //Stream -> Stream Stream<File> fileStream = Stream.of(new File("Ex1.java"), new File("Ex1"), new File("Ex1.bak"), new File("Ex2.java"), new File("Ex1.txt")); Stream<String> filenameStream = fileStream.map(File::getName); // (File객체 f ) -> f.getName() filenameStream.forEach(System.out::println); // 스트림의 모든 파일의 이름을 출력 fileStream.map(File::getName)// 파일 자체가 담긴 스트림을 파일이름(String)의 스트림으로 바꾸고 .filter(s->s.indexOf('.') != -1)//확장자가 없는 파일명은 제외하고 .map(s->s.substring(s.indexOf('.')+1))//. 뒤에 확장자 이름만 추출하고 ,map(String::toUpperCase)//이를 대문자로 변환 .distinct()// 중복값 제거 .forEach(System.out::print); //JAVABAKTXT
- peek()
- 스트림의 요소를 소비하지 않고 엿보기
- 주로 스트림 작업이 잘 이루어 지는지를 확인하는 용도로 쓰인다.
- Stream
peek(Consumer action // 중간연산(스트림의 요소 소비 X) - void forEach(Consumer
action) // 최종 연산(스트림의 요소 소비 O) fileStream.map(File::getName) .filter(s -> s.indexOf('.')!--1) .peek(s-> System.out.printf("filename=%s%n", s)) // 파일명 출력 .map(s -> s.substring(s.indexOf('.')+1)) //확장자만 추출 .peek(s -> System.out.printf("extension=%s%n", s)) // 확장자를 출력한다. .forEach(System.out.println); // 최종연산 스트림을 준비
6.flatMap() - 스트림의 스트림을 스트림으로 변환하는데 사용한다. - Stream<String[]> strArrStrm = Stream.of(new String[]{“abc”, “def”, “ghi”}, new String(“ABC”, “GHI”, “JKLMN”))
- Stream<Stream<String>> strStrStrm = strArrStrn.map(Arrays::stream);//(arr)->Arrays.stream(arr)
- map은 요소 전달받은 값 자체를 스트림으로 만들어준다. 때문에 배열 arr을 하나의 Stream으로 만들고 이를 감싸는 스트림의 요소로 넣는다.
![[Pasted image 20220814163130.png]]
-Stream<String> strStrStrm = strArrStrm.flatMap(Arrays::stream);
- map과 달리 flatMap은 주어지는 배열 arr자체가 아니라 arr의 요소들을 모아 하나의 스트림으로 담아주는 기능을 한다.
![[Pasted image 20220814163153.png]]
- 예시로 살펴보기
Stream<String[]> strArrStrm = Stream.of(new String[]{"abc", "def", "jkl"}, new String[]{"ABC", DEF", "JKL"} ); Stream<Stream<String>> strStrmstrm = strArrStrm.map(Arrays::stream); Stream<String> strStrm = strArrStrm.flatMapp(Arrays::stream); strStrm.map(String::toLowerCase) .distinct() .sort() .forEach(System.out::println); String lineArr{ "Believe or not It is true", "Do or do not There is no try", }; Stream<String> lineStream = Arrays.steram(lineArr); lineStream.flatMap(lin -. Stream.of(line.split(" +"))) .map(Strig::toLowerCase) .distinct() .sorted() .forEach(System.out::println); }
최종연산 살펴보기
- 최종 연산은 스트림의 요소를 소모하여 최종 결과값을 반환하는 스트림 메서드를 의미한다. 1. forEach(), forEachOrdered() ```java void forEach(Consumer<T> action) // 병렬 스트림인 경우 순서가 보장되지 않음 void forEachOrdered(Consumer<T> action) // 병렬스트림인 경우에도 순서 보장됨 ``` ```java IntStream.range(1,10).sequential().forEach(System.out::print);//12345 IntStream.range(1,10).sequential().forEachOrdered(System.out::print);//12345
IntStream.range(1,10).parallel().forEach(System.out::print);//41325 IntStream.range(1,10).parallel().forEachOrdered(System.out::print);//12345
2. allMatch(), anyMatch(), noneMatch()
```java
boolean allMatch(Predicate<T> predicate)
boolean anyMatch(Predicate<T> predicate)
boolean noneMatch(Predicate<T> predicate)
- 각각 모든 요소 만족 / 한 요소라도 만족하면 / 모든 요소가 만족하지 않으면 의 조건을 확인한다.
boolean hasFailedStu = stuStream.anyMatch(s->s.getTotalScore()*<=100);
- findFirst), findAny()
Optional<T> findFirst() //첫번째 요소를 반환, 순차 스트림에 사용 Optional<T> findAny() // 아무거나 하나를 반환. 병렬 스트림에 사용
Optional<Student>result = stuStream.filter(s -> s.getTotalScore()<100). findFirst(); //filter의 조건을 만족하는 첫 요소를 반환 Optionall<Student>result = parallelStream.filter(s -> s.getTotalScore()<100).findAny() //filter의 조건을 만족하는 요소들 중 랜덤으로 한개 반환
- reduce()
- 스트림의 요소를 하나씩 줄여가며 누적연산 수행
```java
Optional
reduce(BinaryOperator accumulator) T reduce(T identity, BinaryOperator accumulator) U reduce (U identity, BiFunction<U,T,U> accumulator, BinaryOperator combiner)
identity : 초기값 accumulator : 이전 연산결과와 스트림의 요소에 수행할 연산, 즉 어떤 작업을 한 건지 combiner : 병렬처리된 결과를 합치는데 사용할 연산(병렬 스트림)
```java int count = intStream.reduce(0, (a,b) -> a+1); int sum = intStream.reduce(0, (a,b) -> a+b); int max = intStream.reduce(Integer.MIN_VALUE, (a,b) -> a>b ? a : b);//max() int min = intStream.reduce(Integer.MAX_VALUE, (a,b) -> a<b ? a : b);//min()
예시로 이해하기
- 스트림의 요소를 하나씩 줄여가며 누적연산 수행
```java
Optional
String[] strArr = {"Inheritance", "Java", "Lamda", "stream", "OptionalDouble", "IntStream", "count", "sum"};
Stream.of(strArr)
.parallel()
.forEachOrdered(System.out::println);// 병렬 쓰레드로 처리하더라도 순서는 유지
boolean noEmptyStr = Stream.of(strArr).nonMatch(s -> s.lenth()==0);
Optional<String> sWrod = Stream.of(strArr).parallel()//병렬 쓰레드로 작업처리(순서x)
.filter(s -> s.charAt(0)=='s').findAny();//s로 시작하는 값중 아무거나 1개 반환
//Stream<String>을 Stream<Integer>로 변환. (s) -> s.length()
Stream<Integer> intStream1 = Stream.of(strArr).map(String:length);
//배열의 요소를 map()을 활용해 각 요소의 문자열 길이를 스트림으로 반환(Array -> Stream<Integer>)
IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);
int count = intStream1.reduce(0, (a,b) -> a+1)
//초기값(identity) 0에서 시작해 스트림요소(b)가 나올 때 마다 +1 누적실행
int sum = intStream1.reduce(0, (a,b) -> a+b)
//초기값(identity) 0에서 시작해 스트림요소(b)가 나올 때 마다 +b 누적실행
OptionalInt max = intStream3.reduce(Integer::max);//각 요소를 돌아가며 max값을 찾아 반환
OptionalInt min = intStream4.reduce(Integer::min);//각 요소를 돌아가며 min값을 찾아 반환
collector()와 Collectors
- collect()는 Collector를 매개변수로 하는 스트림의 최종연산이다. ```java Obejct collect(Collector collector) // Collector를 구현한 클래스의 객체를 매개변수로 갖는다. Object collect(Supplier supplier, Biconsumer accumulator, Biconsumer combiner)//잘안쓰임 ``` ※ reduce()와 collector()차이 - 전자는 주어지는 스트림의 요소 전체를 소모하여 최종 결과를 반환한다. - 후자는 주어지는 스트림의 요소를 나누고 그룹핑하여 최종결과를 그룹별로 각각 반환한다.
- Collector는 수집(collect)에 필요한 메서드를 정의해 놓은 인터페이스이다.
public interface Collector<T, A, R>{ T(요소)를 A에 누적한 다음, 결과를 R로 변환하여 반환 Supplier<A> supplier(); // StringBuilder::new 누적할 곳(★) BiConsumer<A, T> accumulator(); // (sb, s) -> sb.append(s) 누적방법(★) BinaryOperator<A> combiner(); // (sb1, sb2) -> sb1.append(sb2) 결합방법(병렬) Function<A, R> finisher(); // sb -> sb.toString() 최종변환 Set<Characteristics> characteristics(); // 컬렉터의 특성이 담긴 Set을 반환 // 컬렉터의 특성이 담긴 Set을 반환 }
- 위 예시처럼 collector인터페이스를 직접 구현하기 보다는 Collectors라는 구현 클래스를 활용하는 것이 일밙거이다. 다양한 기능의 컬렉터를 제공한다.
- 변환 : mapping(), toList(), toSet(), toMap(), Tocollecttion(),…
- 통계 : counting(), summingInt(), averagingInt(), maxBy(), minBy(), summarizingInt(),….
- 문자열 결합 : joining()
- 리듀싱 - reducing()
- 그룹화와 분할 - groupingBy(), partitioningBy(), collectingAndThen()
※ collect() :최종연산 / Collector : 인터페이스 / Collectors : 클래스(구현체)
- 위 예시처럼 collector인터페이스를 직접 구현하기 보다는 Collectors라는 구현 클래스를 활용하는 것이 일밙거이다. 다양한 기능의 컬렉터를 제공한다.
스트림을 컬렉션, 배열로 변환
- toList(), : 스트림을 List로
- toSet(), : 스트림을 Set으로
- toMap(), : 스트림을 Map으로
- toCollection(): 스트림을 컬렉션으로(특정 컬렉션 클래스타입으로 만들 때 사용)
List<String> names = stuStream.map(Strudent::getName) //Stream<Student> -> Stream<String>
ArrayList<String> list = names.stream().collect(Collectors.toCollection(ArrayList::new));
//Stream<String> -> ArrayList<String>
Map<String, Person> map = personStream.collect(Collectors.toMap(p -> p.getRegId(), p->p))// Stream<person> -> Map<String, Person>, Map은 키과 값을 따로 지정해 주어야 한다.
- 스트림을 배열로 변환할 경우 toArray() 메서드를 사용하는데 주의를 기울이자
- toArray()의 반환 타입은 Object이다. 원한다면 특정 타입으로 형변환을 직접 해줘야 한다.
- Student[] stuNames = studentStream.toArray(Student[]::new);(O)
- Student[] stuNames = studentStream.toArray(); //에러 발생
- Obejct[] stuNames = studentStream.toArray();
- Student[] stuNames = (Studnet[])studentStream.toArray();//(X)
스트림의 통계
- counting()
- summingInt
- maxBy()
- minBy() ```java long count = stuStream.count(); //스트림의 모든 요소 count long count = stuStream.collect(counting());//import static java.util.stream.Collectors.*; //스트림의 모든 요소를 count하여 위 코드와 같으나 코드를 추가하여 부분 count도 가능하다. ``` ```java long totalScore = stuStream.mapToInt(Student::getTotalScore).sum(); //IntStream의 sum() long totalScore = stuStream.collect(summingInt(Student::getTotalScore)); ``` ```java OptionalInt topScore = studentStream.mapToInt(Student::getTotalScore).max(); Optional<Student> topStudent = stuStream.max(Comparator.comparingInt(Student::getTotalScore)); Optional<Student> topStudent = stuStream.collect(maxBy(Comparator.comparingInt(Student::getTotalScore))); ```
스트림을 리듀싱
- reducing(): collectors를 통해 reduce() 대신 그룹별로 reducing이 가능해진다.
Collector reducint(binaryOperator<T> op) Collector reducing(T identity, BinaryOperator<T> op)//BinaryOperator는 reducing으로 수행할 누적 작업을 의미한다. Collector reducing(U identity, Function<T,U> mapper, BinaryOperator<U> op)//map+reduce //Function은 reducing에 필요한 데이터로 스트림 요소를 변환하는 작업을 의미한다.
```java IntStream intStream = new Random().ints(1,46).distinct().limit(6);
OptionalInt max = intStream.reduce(Integer::max);//전체에 대한 리듀싱
Optional
```java
long sum = intStream.reduce(0,(a,b) - > a+b);
long sum = intStream.collect(reducing(0, (a,b)->a+b));
int grandTotal = stuStream.map(Student::getTotalScore).reduce(0, INteger::sum);
int grandTotal = stuStream.collect(reducing(0, Student::getTotalScore, Integer::sum));
String studentNames = stuStream.map(Student::getName).collect(joining());
String studentNames = stuStream.map(Student::getName).collect(joining( "," ));
String studentNames = stuStream.map(Student::getName).collect(joining( "," , "[" , "]" ));
String studentNames = stuStream.collect(joing(","));//Student의 ㅅoStirng으로 결합
스트림의 그룹화와 분할
partitioningBy()
-partitioningBy() : 스트림의 요소를 2분할
Collector partitioningBy(Predicate predicate)]
Collector partitioningBy(Predicate predicate, Collector downstream)
Map<Boolean, List<Student>> stuBySex = stuStream
.collect(partitioningBy(Student::isMale));
List<Student> maleStudent = stuBySex.get(true);//Map에서 남학생 목록을 얻는다.
List<Student> femaleStudent = stuBySex.get(false)//Map에서 여학생 목록을 얻는다.
Map<Boolean, Long> stuNumBySex = stuStream.collect(partitioningBy(Student::isMale, counting()));
System.out.println("남학생 수 :"+ stuNumBySex.get(true));//남학생 수 : 8
System.out.println("여학생 수 :"+ stuNumBySex.get(false));//여학생 수 : 10
Map<Boolean, Optional<Student>> topScoreBySex = stuStream.collect(partitioningBy(Student::isMale, maxBy(comparingInt(Student::getScore))));
System.out.println("남학생 1등 : "+ topScoreBySex.get(true));//남학생 1등 : Optional[나자바, 남, 1,1,300]]
System.out.println("여학생 1등 : "+ topScoreBySex.get(false));//여학생 1등 : Optional[김지미, 여, 1,1,350]]
Map<Boolean, Map<Boolean, List<Student>>> failedStuBySex = stuStream.collect(partitioningBy(Student::isMale, partitioningBy(s -> s.getScore()<150)));
//1. 성별로 분할 2. 성적으로 분할(150)
List<Student> failedMaleStu = failedStuBySex.get(true).get(true);
List<Student> failedFemaleSt = failedStuBySex.get(false).get(true);
groupingBy()
- groupingBy() : 스트림의 요소를 N 분할 가능
Collector groupingBy(Function classifier) Collector groupingBy(Function classifier, Collector downstream) Collector groupingBy(Function classifier, Supplier mapFactory, Collector dowstream)
Map<Integer, List<Student>> stuByBan = stuStream.collect(groupingBy(Student::getBan, toList()));//학생을 반별로 그룹화 가능
Map<Integer, Map<Integer, List<student>>> stuByHakAndBan = // 다중 그룹화 stuStream.collect(groupingBy(Student::getHak, // 1. 학년별 그룹(Key) groupingBy(Student::getBan) // 2. 반별 그룹화(Value) ));
Map<Integer, Map<Integer, Set<Student.Level>>> stuByHakAndBan = stuStream.collect( groupingBy(Student::getHak, // 1. 학년별 그룹(Key) groupingBy(Student::getBan, // 2. 반별 그룹화(Value이자 Key) mapping(s -> { if(s.getScore()>=200) return Student.Level.HIGH; else if(s.getScore() >=100) return Student.Level.MID; else return Student.Levle.LOW; },// 3.학년별 등급(Value) toSet()) //maping enum Level{HIGH, MID, LOW} // 3-1.학년별 등급을 Set으로 타입을 설정함 ))// groupingBy() ); // collect()
댓글남기기