-
Stream프로그래밍/Java 2022. 5. 4. 22:31
Stream 이란?
연속된 데이터를 처리하는 Operation(조작)의 모임.
컬렉션 이나 배열 등에 저장되어 있는 요소들을 하나씩 참조하며 반복적인 처리를 가능케 하는 기능이다.
Stream 을 이용한다면 불필요한 반복문이나 분기처리를 쓰지 않고도 직관적인 코드를 작성할 수 있다.
Stream 특징
- 데이터를 담고 있는 저장소(컬렉션)이 아니다.
- Functional in nature, 즉 Stream 이 처리하는 데이터 소스를 변경하지 않는다.
- 무제한일 수도 있다.
- 실시간으로 계속해서 Stream 으로 들어온 데이터를 Stream 으로 받아 처리할 수 있다.
- Short Circuit 메소드를 사용해서 제한하는 것도 가능하다.
- 중개 오퍼레이션들은 근복적으로 Lazy 하다.
- Stream API 는 크게 중계 오퍼레이션과 터미널 오퍼레이션, 두 가지로 나눌 수 있다.
- 이 둘의 뜻은 계속 이어지는 오퍼레이션, 종료시키는 오퍼레이션을 뜻한다.
- 이 둘의 가장 큰 차이는 Stream return 여부에 있다.
- 손쉽게 병렬처리 할 수 있다.
스트림 파이프 라인
- 0 또는 다수의 중개 오퍼레이션 (intermediate operation)과 한개의 종료 오퍼레이션 (terminal operation) 으로 구성한다.
- Stream 의 데이터 소스는 오직 터미널 오퍼레이션을 실행할 때에만 처리한다.
중개 오퍼레이션
- Stream 을 리턴한다.
- Stateless / Stateful 오퍼레이션으로 더 상세하게 구분할 수도 있다.
(대부분은 Stateless 지만, distinct 나 sorted 처럼 이전 소스 데이터를 참조해야하는 오퍼레이션은 Stateful 오퍼레이션이다.) - fillter, map, skip, sorted, ...
종료 오퍼레이션
- Stream 을 리턴하지 않는다.
- collect, allMatch, count, forEach, min, max, ...
parallelStream( )
- 일반 for 문과 if 문으로 구성된 코드를 stream 혹은 parallelStream 으로 변경해보자.
public class Main { public static void main(String[] args) { List<String> names = new ArrayList<>(); names.add("hyokeun"); names.add("and"); names.add("jungkeung"); // 적용 전 for (String name: names) { if (name.startsWith("h")) { System.out.println(name.toUpperCase()); } } // 적용 후 names.parallelStream().filter(s -> s.startsWith("h")).map(String::toUpperCase) .collect(Collectors.toList()).forEach(System.out::println); } }
- parallelStream 은 멀티 쓰레드를 사용하여 데이터를 처리하는 함수인데, 무조건 좋은것은 아니다.
- 쓰레드를 생성하고 자원 수집, 컨텍스트 스위칭 비용 등을 고려한 후 데이터가 방대하게 큰 경우에 stream 과 직접 성능 비교 한 후 사용하는것이 올바르다 .
Stream 실습
package com.study.java8to11; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamStudy { public static void main(String[] args) { List<OnlineClass> springClasses = new ArrayList<>(); springClasses.add(new OnlineClass(1, "spring boot",true)); springClasses.add(new OnlineClass(2, "spring data jpa",true)); springClasses.add(new OnlineClass(3, "spring mvc",false)); springClasses.add(new OnlineClass(4, "spring core",false)); springClasses.add(new OnlineClass(5, "rest api dev",false)); System.out.println("spring 으로 시작하는 수업"); springClasses.stream() .filter(s -> s.getTitle().startsWith("spring")) .forEach(s -> System.out.println(s.getId())); System.out.println("close 되지 않은 수업"); springClasses.stream() .filter(Predicate.not(OnlineClass::isClosed)) .forEach(s -> System.out.println(s.getId())); System.out.println("수업 이름만 모아서 스트림 만들기"); springClasses.stream() .map(OnlineClass::getTitle) .forEach(System.out::println); List<OnlineClass> javaClasses = new ArrayList<>(); javaClasses.add(new OnlineClass(6, "The Java, Test",true)); javaClasses.add(new OnlineClass(7, "The Java, Code manipulation",true)); javaClasses.add(new OnlineClass(8, "The Java, 8 to 11",false)); List<List<OnlineClass>> hyokeunEvents = new ArrayList<>(); hyokeunEvents.add(springClasses); hyokeunEvents.add(javaClasses); System.out.println("두 수업 목록에 들어있는 모든 수업 아이디 출력"); hyokeunEvents.stream() .flatMap(Collection::stream) .forEach(s -> System.out.println(s.getId())); System.out.println("10부터 1씩 증가하는 무제한 스트림 중에서 앞에 10개 빼고 최대 10개 까지만"); Stream.iterate(10 ,i -> i + 1) .skip(10) .limit(10) .forEach(System.out::println); System.out.println("자바 수업 중에 Test가 들어있는 수업이 있는지 확인"); boolean test = javaClasses.stream().anyMatch(oc -> oc.getTitle().contains("Test")); System.out.println(test); System.out.println("스프링 수업 중에 제목에 spring 이 들어간 제목만 모목서 List로 만들기"); springClasses.stream() .map(OnlineClass::getTitle) .filter(t -> t.contains("spring")) .collect(Collectors.toList()) .forEach(System.out::println); } }
참고
'프로그래밍 > Java' 카테고리의 다른 글
Date와 Time API (0) 2022.05.05 Optional (0) 2022.05.05 Lombok 동작원리 (0) 2022.05.03 다이나믹 프록시 (0) 2022.05.03 클래스 로더 (class loader) (0) 2022.05.01