JAVA - Stream API

TopOfTheHead·2025년 9월 29일

자바 ( JAVA )

목록 보기
16/23

Java Stream API : java.util.Stream
Java 8에서 추가된 기능으로서 람다식을 이용하여 컬렉션 데이터들을 가공 및 처리하여 원하는 값으로 반환하는 인터페이스
I/O Stream과는 다른 개념

데이터 처리 파이프라인으로서 데이터를 연속적으로 람다식을 통해 필터링 , 변환 , 집계 등을 효율적이고 간결하게 처리
배열, Collection객체에 대해 메서드람다식을 통해 여러개를 조합해서 원하는 결과를 필터링해서 처리 및 도출

Stream API 특징

  • 람다식을 이용한 기술이므로 일회성의 특징이 있어 불변의 특성을 가진다.
    ▶ 또한 중간연산마다 새로운 Stream 객체를 생성하므로 불변 특징을 가짐.
    병렬프로그래밍에 유용

  • 사이드이펙트를 방지하기 위해 Stream 람다식순수함수의 특징을 가진다.
    Stream람다식 밖의 지역변수 참조 시 반드시 상수이거나 final로 선언되어 값이 변경되지않는 불변변수만 참조가능
    Side Effect 방지

    Stream람다식와부변수를 재할당 시 컴파일 에러 발생

    외부변수메소드를 통해 외부 변수 상태를 변경하는 경우( 자료구조 객체 등 )도 있으므로 사이드 이펙트를 완전히 예방할 수 없다.
List<Integer> src = List.of(1,2,3);
List<Integer> sink = new ArrayList<>();
src.stream().forEach(sink::add); // 외부변수 상태를 변환

List<Integer> sink 는 선언 이후 재할당이 없으므로 effectively final
stream람다식에서 참조가능

불변성이 없는 자료구조 객체 내부에 데이터를 추가하므로 상태를 변화

  • 원본 데이터를 기반으로 별도의 Stream 인터페이스 구현체를 생성하여 데이터를 가공하므로 원본데이터는 변경하지 않는다
    불변 Collection 객체 ( = 자료구조.of(데이터, ...) )를 원본으로 java.util.streamStream Interface 구현체로 새로 생성하여 데이터 처리 후 새로운 Collection 객체로 결과 도출이 가능

  • 배열( int[] 등 )은 Stream 으로 직접 변환이 불가능
    ▶ 보통 java.util.Arrays 클래스static method : Arrays.stream(배열객체)를 통해 Stream 객체로 변환 후 사용

  • Stream반복문 처리는 순수 반복문에 비해 느리지만 사용성은 매우 뛰어남
    ▶ 성능이 필요한 작업에 한해서만 순수반복문을 사용하고 대부분의 작업은 Stream을 사용

  • StreamDataSource ( 여러 자료형배열, Collection )를 추상화 및 자주 활용되는 유용한 Method가 사전에 정의
    ▶ 기존 순수반복문과 다르게 Data Source에 종속되지않고 같은 방식으로 다룰 수 있어 코드 재사용성이 높아짐

Stream Interface 종류

Stream의 Type은 IntStream 등의 primitive typeStream<Integer>Reference Type이 존재
IntStream객체.boxed() : IntStreamStream<Integer>
IntStream객체.mapToObj(String::valueOf)Stream<String>
Stream<>객체.mapToInt(Integer::intValue) : Stream<Integer>IntStream

Stream 구조
스트림 생성 / 중간연산 / 종단연산

Collection객체.stream().filter( (x)->{ x > 0 } ).count()

스트림 생성 : Collection객체.stream()
중간연산 : 스트림객체.filter( (x)->{ x > 0 } )
종단연산 : 스트림객체.count()

  • Stream 생성
    Collection에서 Stream 생성

    Collection객체.stream() :

    Collection을 확장한 ( List 등 )의 자료구조 객체java.util.streamStream Interface객체로 변환

    배열( int[] 등 )은 Stream 으로 직접 변환이 불가능하므로 List로 변환하여 Stream으로 변환
    ▶ 보통 java.util.Arrays 클래스Arrays.stream(배열객체)를 통해 Stream 객체로 변환

    ex) Arrays.stream(int[]배열객체).forEach(System.out::println)
    int[] 객체IntStream 객체로 변환 후 순회하여 콘솔창에 출력
    • Arrays.stream(배열객체) :
      int[] 객체 전달 시 IntStream으로 반환
      IntStream객체.boxed() 적용 시 Stream<Integer>으로 변환

    • Collection객체.stream() :
      ArrayList<Integer> 전달 시 Stream<Integer>으로 반환
      Stream<Integer>객체.mapToInt(Integer::intValue) 적용 시 IntStream으로 변환


  • 중간연산 ( Intermediate Operation )
    。생성된 Stream 객체를 처리하는 연산

    。 모든 Stream은 0개 이상의 중간연산이 존재하며 중간연산이 선언된 순서대로 순차적으로 새로운 Stream을 생성하면서 처리

    。처리된 결과는 종단연산을 통해 결과를 도출한다

    ex ) map() , filter() , ...

  • 종단연산 ( Terminal Oeration )
    중간연산이 수행된 Stream 객체의 결과를 도출하거나 return하는 연산

    ex ) collect() , forEach()...

Stream 객체 중간연산 method
filter()
map() , mapToInt() , mapToLong() , mapToDouble()
flatMap() , flatMapToInt() , flatMapToLong() , flatMapToDouble()
distinct()
sorted()
peek()
limit()
skip()

  • Stream객체.map(람다식)
    Stream 객체데이터를 순회 및 추출하여 람다식의 매개변수로 전달 시 데이터를 처리 후 반환하는 중간연산
    Stream객체.forEach(람다식)과 유사하나, 람다식의 결과를 새로운 Stream의 요소로 포함하여 새로운 Stream 객체를 생성하여 반환

    ex ) Stream객체.stream().map( (student)->{ student.getName } ).forEach( System.out::println )
    map() 연산을 통해 Stream객체 내 데이터를 처리한 새로운 Stream객체를 생성하여 출력

    map을 통한 Stream 형변환

    • Stream객체.mapToInt(람다식)
      Stream<Integer>객체.mapToInt(Integer::intValue)를 통해 Stream<Integer>IntStream으로 변환가능
      Integer 클래스static methodintValue()메소드 참조를 통해 사용
      mapToInt( (s) -> Integer.intValue(s) )와 동일
    Arrays.stream(a).distinct().boxed().sorted(Comparator.reverseOrder())
    				.mapToInt(Integer::intValue).toArray();

    int[]IntStream을 생성 후 boxed()를 통해 Stream<Integer>로 변환 후 내림차순mapToInt()를 통해 IntStream으로 변환하여 int[]로 반환

    • Stream객체.mapToObj(람다식)
      IntStream객체.mapToObj(String::valueOf)를 통해 IntStreamStream<String>으로 변환가능
      IntStream객체.mapToObj(s -> String.valueOf(s))


  • Stream객체.filter(Predicate)
    。특정 조건(Predicate 역할의 람다식)에 해당하는 요소만을 추출하여 새로운 Stream객체를 생성하는데 사용하는 연산
    if문과 유사

    ex) Stream객체.filter(( element )->{ element.no > 10 }).findFirst()
    Stream 객체 내 데이터의 no 변수 중 no > 10을 만족하는 첫번째 데이터를 찾아서 반환

  • Stream객체.distinct()
    Stream객체의 데이터 중 중복을 제거해서 새로운 Stream객체를 반환

  • Stream객체.sorted()
    Stream객체의 데이터를 오름차순으로 정렬한 새로운 Stream객체를 반환
    Stream객체의 요소가 Class Type인 경우 따로 Comparable , Comparator을 정의

    Stream객체.sorted(Comparator객체) :
    오름차순 정렬정렬 수행 시 Comparator 객체를 전달하여 수행

    • Primitive Type에 대해 적용하는 경우
      내림차순 정렬 :
      Stream객체.sorted(Comparator.reverseOrder())
      java.util.Comparator 활용
      IntStream 등의 primitive TypeStream이 아닌 Stream<Integer>Class TypeStream에만 적용이 가능.
    Arrays.stream(a).boxed().sorted(Comparator.reverseOrder())
    				.mapToInt(Integer::intValue)
    				.toArray();

    IntStreamboxed()를 통해 Stream<Integer>로 변환 후 내림차순 정렬mapToInt(Integer::intValue)IntStream로 재변환하여 활용

    • 사용자 정의 Class Type에 대해 적용하는 경우
      。별도로 ClassComparable<T>를 정의하거나 , Comparetor<T> 객체를 생성하여 인자로 전달
      객체간 정렬

    • 번외 : 람다식으로 구현하기
      Comparator람다식 형태로 구현하여 전달이 가능.
    result1.entrySet().stream().
    			sorted((entry1, entry2)-> (int) (entry2.getValue() - entry1.getValue()))
    			.limit(3).map(entry -> entry.getKey() ).toList();


  • Stream객체.boxed()
    IntStream 등의 Primitive TypeStreamStream<Integer>Class TypeStream으로 변환

  • Stream객체.limit(제한할 요소수)
    Stream 객체의 첫 요소부터 제한할 요솟수까지만 가져와서 새로운 Stream 객체 생성

  • Stream객체.skip(요소수)
    Stream 객체의 요소 중 첫 요소부터 설정된 요솟수까지 skip 한 후 이후 요소부터 끝 요소까지 가져와서 새로운 Stream 객체 생성
var names = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
		names.stream().limit(2)
			.forEach(s -> System.out.print(s + " ")); 
            // 1 2
        names.stream().skip(5)
			.forEach(s -> System.out.print(s + " ")); 
            // 6 7 8 9
	}

.

  • Stream객체.flatMap(람다식)
    。중첩된 Stream<Stream<T>>Stream<T>로 변환하는 함수
    람다식을 통해 자료구조 내부 자료구조를 다시 Stream으로 형변환하여 활용
var names = List.of(
			List.of(1, 2, 3),
			List.of(4, 5, 6),
			List.of(7, 8, 9)
		);
		names.stream()
        // 내부 List의 stream을 형변환
			.flatMap(lst -> lst.stream())
			.forEach(s -> System.out.print(s + " ")); 
            // 1 2 3 4 ....

Stream 종단연산
forEach() , forEachOrdered()
reduce()
。배열반환 : collect() , toArray() , toList()
。통계 : min() / max() / count()
。검사 : anyMatch() , allMatch() , noneMatch()
。검색 : findFirst() / findAny()

  • Stream객체.forEach(람다식)
    Stream 객체데이터를 순회 및 추출하여 람다식의 매개변수로 전달하는 종단연산

    Stream객체.map(람다식)과 유사한 기능을 제공하나, 새로운 Stream객체를 생성하지않으므로 반환값이 존재하지 않음
    ▶ 주로 출력용도로 활용됨

    ex ) Stream객체.forEach(System.out::println)

  • Stream객체.max() :
    Stream객체의 데이터 중 가장 큰 값을 가지는 데이터를 참조하는 Optional 객체를 반환
    ex ) Stream객체.max().orElse(0)
    Stream 객체의 데이터 중 최댓값을 return 및 존재하지 않을경우 0을 return

    ex ) Stream객체.max().getAsInt();
    Stream 객체의 데이터 중 최댓값int로 return

  • Stream객체.findFirst() , Stream객체.findAny()
    Stream객체 요소 중 가장 먼저 검색한 요소 반환
    。아무 요소를 반환

    。 해당 Stream 내 검색할 요소가 존재하지않아 Null을 반환할 수 있으므로 Optional객체를 반환

  • Stream객체.allMatch(predicate람다식)
    요소가 모두 predicate 조건에 부합하는 경우 true를 반환

  • Stream객체.anyMatch(predicate람다식)
    요소가 하나라도 predicate 조건에 부합하는 경우 true를 반환

  • Stream객체.noneMatch(predicate람다식)
    요소중 하나라도 predicate 조건에 부합하는경우** false를 반환
var names = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
boolean result1 = names.stream().allMatch((i) -> i > 0); // true
boolean result2 = names.stream().anyMatch((i) -> i == 5); // true
boolean result3 = names.stream().noneMatch((i) -> i == 5); // false

.

  • Stream객체.reduce(초기값, 람다식)
    Stream객체요소를 정의한 기준값부터 정의한 람다식대로 연산 후 결과값을 반환

    기준값을 정의하지않는 경우 Null이 포함될 수 있어 Optional객체가 반환
    • 누적합 :
      Stream객체.reduce( 초기값 , ( x , y )-> x + y )
      람다식메소드참조 : Integer::sum으로 대체가능
    var names = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    int sum = names.stream().reduce(0, (a, b) -> a + b);
    System.out.println(sum); // 55 출력
    • 누적곱 :
      Stream객체.reduce( ( x , y )-> x * y ).get()
    var names = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    		Optional<Integer> sum = names.stream().reduce((x, y) -> x * y);
    		System.out.println(sum.get()); // 3628800 출력


  • Stream객체.toArray()
    Stream 객체배열로 반환

    ex )
    배열 : int[] arr = Stream객체.toArray()
    기본형배열은 자동 형변환 수행

    객체배열 : Student[] stuNames = Stream객체.toArray(Student[]::new);
    Wrapper객체 배열 : Integer[] arr = Stream객체.toArray(Integer[]::new)
    ▶ 자동 형변환이 안되므로 람다식 또는 생성자 메소드 참조를 통해 객체를 생성하는 식을 매개변수로 전달
    ▶ 정의 안할 경우 Object로 생성
    Object[] stunames = Stream객체.toArray();

  • Stream객체.toList()
    JDK 11부터 Stream.collect(Collectors toList())를 단축하기위해 등장한 코드
    Stream<T>List<T>로 반환

  • Stream객체.collect(Collectors 클래스의Static변환메소드)
    java.util.Stream.Collectors를 매개변수로 하여 Stream 객체를 원하는 CollectionTypeCollect하여 반환하는 Stream종단연산 Method
    ▶ 보통 java.util.Stream.Collectors 클래스Static Method와 함께 사용하여 , List, Set , Map등의 다양한 자료구조로 변환하는 용도로 활용

Stream 활용 예제
배열 데이터를 중복을 제거하면서 내림차순으로 정렬 후 반환하는 method 작성

import java.util.Arrays;
import java.util.Comparator;
public class ffff {
	public static void main(String[] args)  {
		int[] a = { 4,2,2,1,3,4 };
		int[] b = solution(a);
		for(int i : b) System.out.print(i);
	}
	public static int[] solution(int[] a) {
		return Arrays.stream(a).distinct().boxed()
				.sorted(Comparator.reverseOrder())
				.mapToInt(Integer::intValue)
				.toArray();
	}
}

Collectors : java.util.Stream.Collectors
Collector API

。주로 Stream객체.collect()의 매개변수로서 Stream 객체의 요소를 원하는 형태의 Collection ( List, Set , Map 등 )으로 변환 시 사용

。추가적으로 Collectors.averagingInt(), Collectors.groupingBy(람다식),
Collectors.partitioningBy(predicate) 의 방식들이 존재

Collection static method
Stream객체collect()의 매개변수로 전달하여 활용
ex ) 스트림객체.collect(Collectors.toList())

  • Stream -> Collection 변환용도의 static method
    • Collectors.toList()
      Stream 객체List<T>로 반환
      Stream에서는 이미 해당 기능이 Stream객체.toList()로 간편하게 구현

    • Collectors.toSet()
      Stream 객체Set<T>로 반환

    • Collectors.toCollection()
      Stream객체Collection으로 생성하여 반환
      ▶ 매개변수에 Collection 객체를 생성하여 반환하는 람다식 or 생성자참조를 정의
      • ArrayList 생성
        Collectors.toCollection(ArrayList::new) : 메소드참조 이용하여 ArrayList<T> 반환


    • Collectors.toMap( Key mapper람다식 , Value mapper람다식 )
      Stream객체의 요소를 각각 KeyValuemapper역할의 람다식을 통해 반환값을 mapping하여 Map<K,V>로 반환
      ex )
      Stream객체.collect(Collectors.toMap(obj->obj.Key로설정할변수 , obj -> obj.Value로설정할변수))

    • Collectors.joining("구분자", "접두사" , "접미사") :
      Stream객체의 모든 요소를 구분자 ( delimiter )를 설정 및 연결하여 하나의 String으로 합쳐서 반환

      。인자로 String만 들어올 수 있으므로 먼저 String으로 캐스팅이 필요
    		int[] A = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
            // IntStream에서 Stream<String>으로 변환
    		String s = Arrays.stream(A).mapToObj(String::valueOf)
    			.collect(Collectors.joining( ",", "[", "]" ));
    		System.out.println(s);
             // [1,2,3,4,5,6,7,8,9,10] 출력
    • Collectors.mapping(mapper람다식 , Collectors.toList())
      Stream 객체에서 특정 요소를 추출한 람다식의 반환값을 List<T>로 포함하여 반환
      T : 람다식의 반환값 Type
    var testSet = List.of(
    			new Edge(1, 4),
    			new Edge(2, 3),
    			new Edge(3, 3),
    			new Edge(4, 6)
    		);
    		List<Integer> result1 = testSet.stream().collect(Collectors
    			.mapping((e) -> e.start, Collectors.toList()));
    		System.out.println(result1);
    		// 1, 2, 3, 4
  • 집계용도의 Collector static method
    • Collectors.counting() / Collectors.maxBy() / Collectors.minBy()
      。각각 Stream객체.count() , Stream객체.max() , Stream객체.min()와 동일한 역할을 수행

    • Collectors.averagingInt(mapper람다식)
      Stream객체Stream<Integer> 요소에 대해 Mapper 역할의 람다식의 반환값을 추출하여 해당 값들의 평균double로 도출

      。입력되는 StreamType에 따라서 다르게 사용.
      Stream<Integer> : averagingInteger()
      Stream<Long> : averagingLong()
      Stream<Double> : averagingDouble()

    • Collectors.summingInt(mapper람다식)
      람다식의 반환값을 통해 해당 값들의 Integer로 도출

      summingInteger() , summingLong() , summingDouble() 이 존재

    • Collectors.summarizingInt(mapper람다식)
      람다식의 반환값을 통해 해당 값들의 통계요약을 IntSummaryStatistics 형식으로 반환
      count , sum , min , average , max의 정보를 포함하여 반환


      summarizingInteger() , summarizingLong() , summarizingDouble() 이 존재
    var testSet = List.of(
    			new Edge(1, 4),
    			new Edge(2, 3),
    			new Edge(3, 4),
    			new Edge(4, 3),
    			new Edge(5, 2),
    			new Edge(6, 1)
    		);
    		int sum = testSet.stream().collect(
    			Collectors.summingInt(edge -> edge.target));
    		double mean = testSet.stream().collect(
    			Collectors.averagingInt(edge -> edge.target));
    		IntSummaryStatistics statistics = testSet.stream().collect(
    			Collectors.summarizingInt(edge -> edge.start));
    		System.out.println(sum); // 2.83333..
    		System.out.println(mean); // 21
    		System.out.println(statistics); // {count=6, sum=21, min=1, average=3.500000, max=6}

Stream을 분류하여 Map<K,V>로 구축하는 static method
Collectors.groupingBy() , Collectors.partitioningBy()

Collectors.groupingBy(classifier , MapFactory , Downstream)
。분류 기준이 되는 Classifier 함수 역할의 람다식의 반환값을 Key로 설정하여 이를 기준으로 Categorization 하여 다수의 그룹을 반환하는 Method

classifier : 그룹화Key를 추출하는 람다식
ex ) ( k ) -> k.score : score 값을 기준으로 요소를 그룹화

mapFactory : 저장할 Map 인터페이스구현클래스생성자를 정의
▶ 향후 생성된 Map 객체는 해당 구현클래스를 기반으로 함.
ex ) TreeMap::new , HashMap::new
default : HashMap
TreeMap 설정 시 classifier 기준 정렬수행

downstream : classifier 기준 그룹별로 분할한 요소의 추가 가공을 정의
Collectorstatic method 설정

  • Collectors.groupingBy(classifier람다식)
    반환타입 : Map<K,List<T>>를 반환
    K : 람다식결과 Type
    T : Stream 요소 Type

    ex ) Edgestart를 기준으로 분류를 수행하는 경우
    start도메인을 기준으로 Key = { 1 , 4 }로서 그룹을 분할
		var testSet = List.of(
			new Edge(1, 4),
			new Edge(1, 3),
			new Edge(4, 3),
			new Edge(4, 6)
		);
		Map<Integer, List<Edge>> e = testSet.stream().collect(Collectors.groupingBy(edge -> edge.start));
		// {1=[Edge{start=1, target=4}, Edge{start=1, target=3}], 4=[Edge{start=4, target=3}, Edge{start=4, target=6}]}
		List<Edge> a = e.get(4);
		// [Edge{start=4, target=3}, Edge{start=4, target=6}]
		System.out.println(a.get(0).target); // 3
     .
  • Collectors.groupingBy(classifier람다식, MapFactory ,DownStream)
    DownStream에 원하는 Collector static 메소드를 정의하여 classifier로 분류된 각 그룹별 집계를 도출

    Map<K, D>를 반환
    K : 람다식결과 Type
    D : Collector static 메소드의 결과 Type
var testSet = List.of(
			new Edge(1, 4),
			new Edge(1, 3),
			new Edge(4, 3),
			new Edge(4, 6)
		);
		Map<Integer, Integer> result1 = testSet.stream()
			.collect(Collectors.groupingBy(e -> e.start,
				TreeMap::new,
				Collectors.summingInt(e -> e.target)));
		System.out.println(result1); // {1=7, 4=9}

Map 자료구조 구현체 : TreeMap으로 설정됨

DownStreamCollectors.toMap(Mapper1, Mapper2)를 적용하는 경우
Classfier에 의해 분류 및 분류결과를 Map<K,V>로서 Mapping을 수행
Map<K,Map<K,V>> 를 반환

var testSet = List.of(
			new Edge(1, 4),
			new Edge(2, 3),
			new Edge(3, 3),
			new Edge(4, 6)
		);
		Map<Integer, Map<Integer, Integer>> result1 = testSet.stream()
			.collect(Collectors.groupingBy(e -> e.start,
				Collectors.toMap(k -> k.start, v -> v.target)));
		System.out.println(result1); // {1={1=4}, 2={2=3}, 3={3=3}, 4={4=6}}

Collectors.partitioningBy(predicate , Downstream)
Predicate역할 람다식을 기준으로 True / false로 그룹화한 후 Map형태로 반환

기본값으로 Map<Boolean,List<T>>로 반환
T : Stream 요소
Downstream 정의 시 List<T>Downstream의 결과값으로 설정

var testSet = List.of(
			new Edge(1, 4),
			new Edge(1, 3),
			new Edge(4, 3),
			new Edge(4, 6)
		);
		Map<Boolean, List<Edge>> result1 = testSet.stream().collect(
			Collectors.partitioningBy((e) -> e.start > 2)
		);
		System.out.println(result1);
		// {false=[Edge{start=1, target=4}, Edge{start=1, target=3}], true=[Edge{start=4, target=3}, Edge{start=4, target=6}]}
		List<Edge> result2 = result1.get(true);
		System.out.println(result2);
		// [Edge{start=4, target=3}, Edge{start=4, target=6}]

Collectors.groupingBy 연습문제

  • test set
class Exam implements Comparable<Exam> {
	String studentname;
	int score;
	boolean isPass;
	public Exam(String studentname, int score) {
		this.studentname = studentname;
		this.score = score;
	}
	@Override
	public int compareTo(Exam o1) {
		return this.score - o1.score;
	}
	@Override
	public String toString() {
		return "Exam{" +
			"studentname='" + studentname + '\'' +
			", score=" + score +
			'}';
	}
}
var examList = List.of(
			new Exam("일정수", 50),
			new Exam("이정수", 60),
			new Exam("삼정수", 10),
			new Exam("사정수", 20),
			new Exam("오정수", 30),
			new Exam("육정수", 80),
			new Exam("칠정수", 90),
			new Exam("팔정수", 100),
			new Exam("구정수", 60),
			new Exam("십정수", 10),
			new Exam("십일정수", 30),
			new Exam("십이정수", 50),
			new Exam("십삼정수", 70),
			new Exam("십사정수", 90)
		);
  • Q. 점수별로 분류 후 90점 이상인 학생의 이름을 출력
// 점수별로 분할된 Map객체를 return
		Map<Integer, List<Exam>> result1 = examList.stream().collect(Collectors.
			groupingBy((exam) -> exam.score));
		// Map객체에서 90점 이상인 사람의 이름을 출력
		result1.entrySet().stream().filter(entry -> entry.getKey() >= 90)
			.flatMap(entry -> entry.getValue().stream())
			.forEach(exam -> System.out.println(exam.studentname));
       //  팔정수 칠정수 십사정수

MapMap.Entry<K,V> 객체로 구성
Map 자료구조stream으로 활용하는 경우 Map객체.entrySet().stream()으로 Stream<Map.Entry<K,V>>으로 변환해야한다.

flatMap()으로 작업 수행 시 entry.getValue() : List<Exam>이므로 Stream<Exam>으로 변환
▶ 이후 Stream<Map.Entry<K,V>>Stream<Exam>으로 변환됨.

  • Q. 점수별로 분류 후 점수별 몇명인지 출력
Map<Integer, Long> result1 = examList.stream().collect(Collectors.groupingBy(
			(e) -> e.score, Collectors.counting()
		));
		System.out.println(result1);
		// {80=1, 50=2, 100=1, 20=1, 70=1, 90=2, 10=2, 60=2, 30=2}
  • Q. 점수별로 분류 후 오름차순 정렬인 점수별 사람들의 이름을 출력
    classifier : 점수를 기준으로 분류

    Map 인터페이스 구현체TreeMap::new 생성자를 통해 생성된 TreeMap 객체를 기반으로 업캐스팅하여 구현
    classifier 기준 오름차순정렬

    Collectors.mapping()을 통해 분류가 완료된 그룹별로 이름에 해당하는 데이터를 추출하여 List<String>으로 재구성
Map<Integer, List<String>> result1 = examList.stream().collect(Collectors.groupingBy((
			(e) -> e.score), TreeMap::new, Collectors.mapping(s -> s.studentname, Collectors.toList())
		));
		System.out.println(result1);
		// {10=[삼정수, 십정수], 20=[사정수], 30=[오정수, 십일정수], 50=[일정수, 십이정수], 60=[이정수, 구정수], 70=[십삼정수], 80=[육정수], 90=[칠정수, 십사정수], 100=[팔정수]}
  • Q. partitioningBy()를 사용하여 60점 이상인 사람의 평균 도출
Map<Boolean, Double> result1 = examList.stream().collect(
			Collectors.partitioningBy((e -> e.score >= 60),
				Collectors.averagingInt((e) -> e.score))
		);
		System.out.println(result1.get(true));
		// 78.5714...
profile
공부기록 블로그

0개의 댓글