Stream

박주현·2022년 11월 2일
0

국비 공부

목록 보기
25/44

스트림

  • JDK 8부터 새롭게 추가된 기능으로 데이터 집합체를 반복적으로 처리
  • 스트림을 이용하면 닷의 스레드 코드를 구현하지 않아도 병렬로 처리
  • 스트림은 스트림 데이터와 스트림 연산을 모두 포함

컬렉션과 스트림의 차이

컬렉션과 스트림

  • 컬렉션이 데이터의 공간적 집합체라면, 스트림은 데이터의 시간적 집합체이다.
  • 컬렉션은 데이터 원소의 효율적인 관리와 접근에 맞게 설계되어 있지만, 스트림은 데이터 원소에서 수행할 함수형 연산에 맞게 설

스트림의 종류와 생성

숫자 스트림과 객체 스트림의 차이

  • 숫자 스트림은 평균, 합계를 반환하는 average(), sum()이라는 메서드가 있다.
  • 객체 스트림이 제공하는 최종 연산이 Optional 타입을 반환한다면 숫자 스트림은 OptionalInt, OptionalLong, OptionalDouble 타입을 반환한다.
  • 숫자 스트림은 데이터 스트림의 기본 통계 요약을 나타내는 summaryStatistics() 메서드를 제공한다.

스트림 생성


스트림의 파이프 라인


스트림의 병렬 처리

  • 멀티 코어 CPU를 제대로 활용하여 데이터 소스를 병렬로 처리할 수 있도록 병렬 스트림도 지원
  • 컬렉션 혹은 스트림으로부터 각각 parallelStream() 혹은 parallel() 메서드를 호출하여 병렬 스트림 획득
  • 스트림을 부분 스트림으로 분할하기 어렵거나 데이터 소스의 크기가 작거나 혹은 싱글 코어 CPU 라면 오히려 성능이 나빠질수 있다.
import java.util.stream.IntStream;

public class ParallelDemo {
	public static void main(String[] args) {
		long start, end, total;

		IntStream sequantial = IntStream.rangeClosed(1, 100_000_000);
		start = System.currentTimeMillis();
		total = sequantial.sum();
		end = System.currentTimeMillis();
		System.out.println("순차 처리 : " + (end - start));

		IntStream parallel = IntStream.rangeClosed(1, 100_000_000).parallel();
		start = System.currentTimeMillis();
		total = parallel.sum();
		end = System.currentTimeMillis();
		System.out.println("병렬 처리 : " + (end - start));
	}

}

스트림 활용

filtering

import java.util.stream.IntStream;
import java.util.stream.Stream;

import sec01.Nation;
import sec01.Util;

public class FilterDemo {
	public static void main(String[] args) {
    	// 가변 인수이기에 인수의 갯수가 정해져 있지 않다.
		Stream<String> s1 = Stream.of("a1", "b1", "b2", "c1", " c2", "c3");
		Stream<String> s2 = s1.filter(s -> s.startsWith("c"));
		Stream<String> s3 = s2.skip(1);
		System.out.print("문자열 스트림 : ");
		s3.forEach(Util::print);
		
        // 가변 인수이기에 인수의 갯수가 정해져 있지 않다.
		IntStream i1 = IntStream.of(1, 2, 1, 3, 3, 2, 4);
		IntStream i2 = i1.filter(i -> i % 2 == 0);
		IntStream i3 = i2.distinct();
		System.out.print("\n정수 스트림");
		i3.forEach(Util::print);

		System.out.print("\n인구가 1억(100백만) 이상의 2개 나라 : ");
		Stream<Nation> n1 = Nation.nations.stream();
		Stream<Nation> n2 = n1.filter(p -> p.getPopulation() > 100.0);
		Stream<Nation> n3 = n2.limit(2);
		n3.forEach(Util::print);

	}

}

Mapping

import java.util.stream.IntStream;
import java.util.stream.Stream;

import sec01.Util;

public class Map1Demo {
	public static void main(String[] args) {
		Stream<String> s1 = Stream.of("a1", "b1", "b2", "c1", "c2");

		Stream<String> s2 = s1.map(String::toUpperCase);
		s2.forEach(Util::print);
		System.out.println();

		Stream<Integer> i1 = Stream.of(1, 2, 1, 3, 3, 2, 4);

		Stream<Integer> i2 = i1.map(i -> i * 2);
		i2.forEach(Util::print);
		System.out.println();

		Stream<String> s3 = Stream.of("a1", "a2", "a3");

		Stream<String> s4 = s3.map(s -> s.substring(1));

		IntStream i3 = s4.mapToInt(Integer::parseInt);

		Stream<String> s5 = i3.mapToObj(i -> "b" + i);

		s5.forEach(Util::print);

	}

}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class Map3Demo {
	public static void main(String[] args) {
		List<String> list1 = List.of("안녕", "자바!", "잘 가, C++!");
		Stream<String> s1 = list1.stream();
		Stream<String> s2 = s1.flatMap(s -> Arrays.stream(s.split(" ")));
		s2.forEach(Util::printWithParenthesis);
		System.out.println();

		List<String> list2 = List.of("좋은 아침");
		List<String> list3 = List.of("안녕! 람다", "환영! 스트림");

		Stream<List<String>> s3 = Stream.of(list1, list2, list3);
		Stream<String> s4 = s3.flatMap(list -> {
			if (list.size() > 1) {
				return list.stream();
			} else {
				return Stream.empty();
			}
		});
		s4.forEach(Util::printWithParenthesis);
	}

}

매칭과 검색

특정 속성과 일치되는 스트림 원소의 존재 여부를 조사하거나 검색하는 데 사용되는 스트림의 최종 연산

리듀싱 연산

  • 원소 개수, 합계, 평균값 등과 같은 단순 집계가 아니라면 자바 API가 제공하는 기본 집계 연산으로 감당할수 없다.
  • 이를 위하여 Stream 인터페이스는 람다식을 사용하여 복합적인 집계 결과를 도출할 수 있도록 리듀싱 기능을 제공한다.
  • 리듀싱 연산은 스트림원소를 단 하나의 값으로 축약시키는 연산이다.

import java.util.DoubleSummaryStatistics;
import java.util.stream.DoubleStream;
import java.util.stream.Stream;

import sec01.Nation;

public class Reduce2Demo {
	public static void main(String[] args) {
		Stream<Nation> s1 = Nation.nations.stream();
		// China
		s1.reduce((n1, n2) -> n1.getPopulation() > n2.getPopulation() ? n1 : n2).ifPresent(System.out::println);

		Stream<Nation> s2 = Nation.nations.stream();
		double sumOfPopulation = s2.filter(n -> n.getGdpRank() <= 20).mapToDouble(n -> n.getPopulation()).reduce(0.0,
				(n1, n2) -> n1 + n2);

		// 리스트에서 GDP가 20위 이내의 나라의 인구 총합은 1789.7백만명이다.
		System.out.println("리스트에서 GDP가 20위 이내의 나라의 인구 총합은 " + sumOfPopulation + "백만명이다.");

		Stream<Nation> s3 = Nation.nations.stream();
		DoubleStream ds = s3.mapToDouble(Nation::getPopulation);
		DoubleSummaryStatistics dss = ds.summaryStatistics();
		// DoubleSummaryStatistics{count=8, sum=1956.800000, min=4.500000, average=244.600000, max=1355.700000}
		System.out.println(dss);

	}

}

옵션 타입

  • String과 Date는 상속 관계가 아닌데도 null?
String s = null;
Date d = null;
  • java.util 패키지 소속
  • Optional은 null을 사용하지 않고 부재 값을 포함한 데이터를 저장하는 클래스로써 값의 존재 여부에 따라 다양하게 처리할 수 있는 기능을 제공
  • 종류 : Optional, OptionalInt, OptioanlLong, OptionalDouble


Collect

0개의 댓글