BackEnd/Java
Java8. 스트림 (Stream)
hanseom
2022. 1. 22. 06:29
반응형
스트림(Stream)이란 순차 또는 병렬 집계 작업을 지원하는 오퍼레이션들의 모음입니다(Sequence of elements supporting sequential and parallel aggregate operations).
스트림의 특징
- 데이터를 담고 있는 저장소(Collection)가 아닙니다.
- Functional in nature, 스트림이 처리하는 데이터 소스를 변경하지 않습니다.
- 스트림으로 처리하는 데이터는 오직 한 번만 처리됩니다.
- 무제한일 수도 있습니다. (Short Circuit 메소드를 사용해서 제한할 수 있습니다.)
- 중개 오퍼레이션은 근본적으로 lazy 합니다. (lazy하다는 것은 종료 오퍼레이션이 오기 전까지 실행되지 않는 것을 의미합니다.)
- 손쉽게 병렬 처리할 수 있습니다. (단, 쓰레드 생성 및 컨텍스트 스위치 비용으로 무조건 병렬 처리가 빠르지는 않습니다.)
스트림 파이프라인
- 0 또는 다수의 중개 오퍼레이션과 한 개의 종료 오퍼레이션으로 구성합니다.
- 스트림의 데이터 소스는 오직 종료 오퍼레이션을 실행할 때만 처리합니다.
중개 오퍼레이션 (Intermediate operation)
filter, map, limit, skip, sorted 등 Stream을 리턴합니다.
종료 오퍼레이션 (Terminal operation)
collect, allMatch, count, forEach, min, max 등 Stream을 리턴하지 않습니다.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamBasic {
public static void main(String[] args) {
List<String> stream = new ArrayList<>();
stream.add("Ballantines");
stream.add("Macallan");
stream.add("Royal Salute");
stream.add("Scotch Blue");
stream.add("Johnnie Walker");
// 모든 문자를 대문자로 변환합니다.
Stream<String> stringStream = stream.stream().map(String::toUpperCase);
System.out.println("=================[Functional in nature]=================");
System.out.println("=== 기존 데이터 소스를 변경하지 않습니다.===");
stream.forEach(System.out::println);
System.out.println("===모든 문자를 대문자로 변환합니다.===");
stringStream.forEach(System.out::println);
System.out.println("========================================================");
System.out.println("=========================[lazy]=========================");
Stream<String> lazyStream = stream.stream().map((s) -> {
System.out.println("중개 오퍼레이션: " + s);
return s.toLowerCase();
});
System.out.println("===종료 오퍼레이션 이후 실행됩니다.===");
lazyStream.forEach(System.out::println);
System.out.println("========================================================");
System.out.println("================[병렬 처리 (parallelStream)]===============");
System.out.println("===병렬처리 시 처리하는 Thread를 출력하고, 모든 문자를 소문자로 출력합니다.===");
List<String> collect = stream.parallelStream().map((s) -> {
System.out.println(s + " " + Thread.currentThread().getName());
return s.toLowerCase();
}).collect(Collectors.toList());
System.out.println("===모든 문자를 소문자로 변환합니다.===");
collect.forEach(System.out::println);
System.out.println("========================================================");
}
}
/*******************************************************
[결과]
=================[Functional in nature]=================
=== 기존 데이터 소스를 변경하지 않습니다.===
Ballantines
Macallan
Royal Salute
Scotch Blue
Johnnie Walker
===모든 문자를 대문자로 변환합니다.===
BALLANTINES
MACALLAN
ROYAL SALUTE
SCOTCH BLUE
JOHNNIE WALKER
========================================================
=========================[lazy]=========================
===종료 오퍼레이션 이후 실행됩니다.===
중개 오퍼레이션: Ballantines
ballantines
중개 오퍼레이션: Macallan
macallan
중개 오퍼레이션: Royal Salute
royal salute
중개 오퍼레이션: Scotch Blue
scotch blue
중개 오퍼레이션: Johnnie Walker
johnnie walker
========================================================
================[병렬 처리 (parallelStream)]===============
===병렬처리 시 처리하는 Thread를 출력하고, 모든 문자를 소문자로 출력합니다.===
Ballantines ForkJoinPool.commonPool-worker-23
Macallan ForkJoinPool.commonPool-worker-19
Royal Salute main
Johnnie Walker ForkJoinPool.commonPool-worker-5
Scotch Blue ForkJoinPool.commonPool-worker-9
===모든 문자를 소문자로 변환합니다.===
ballantines
macallan
royal salute
scotch blue
johnnie walker
========================================================
*******************************************************/
Stream API
스트림 생성 (Iterate)
import java.util.stream.Stream;
public class StreamAPI {
public static void main(String[] args) {
// 1부터 1씩 증가하는 무제한 숫자 스트림에서 5개를 skip하고 최대 5개를 가져온다.
Stream.iterate(1, i -> i + 1)
.skip(5)
.limit(5)
.forEach(System.out::println); // [결과] 6 7 8 9 10
}
}
스트림 필터 (Filter)
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.List;
public class StreamAPI {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(6, "Daol"));
list.add(new Person(4, "Iden"));
list.add(new Person(3, "Jena"));
// Filter(Predicate)
// 이름이 "D"로 시작하는 Person 필터링
list.stream()
.filter(s -> s.getName().startsWith("D"))
.forEach(s -> System.out.println(s.getName())); // [결과]: Daol
}
}
스트림 변경 (Map / FlatMap)
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class StreamAPI {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(6, "Daol"));
list.add(new Person(4, "Iden"));
list.add(new Person(3, "Jena"));
// Map(Function)
// Person에서 String name만 새로운 스트림으로 반환합니다.
list.stream()
.map(Person::getName)
.forEach(System.out::println); // [결과]: Daol Iden Jena
// FlatMap(Function)
// 신규 list를 생성합니다.
List<Person> newList = new ArrayList<>();
newList.add(new Person(35, "Hanseom"));
// list를 담고 있는 flatMapList 생성합니다.
List<List<Person>> flatMapList = new ArrayList<>();
flatMapList.add(list);
flatMapList.add(newList);
// 모든 원소(list / newList)를 단일 원소로 변환합니다.
flatMapList.stream()
.flatMap(Collection::stream)
.forEach(s -> System.out.println(s.getName())); // [결과]: Daol Iden Jena Hanseom
}
}
스트림 검사 (anyMatch() / allMatch() / nonMatch())
import java.util.ArrayList;
import java.util.List;
public class StreamAPI {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(6, "Daol"));
list.add(new Person(4, "Iden"));
list.add(new Person(3, "Jena"));
// 이름 중에 "a"가 포함된 문자열이 있는지 확인합니다.
boolean bool = list.stream()
.anyMatch(s -> s.getName().contains("l"));
System.out.println(bool); // [결과]: true
}
}
스트림 집계 (collect() / sum() / max() / count())
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamAPI {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(6, "Daol"));
list.add(new Person(4, "Iden"));
list.add(new Person(3, "Jena"));
// 이름에 "a"가 포함된 새로운 list를 만듭니다.
List<String> aList = list.stream().filter(s -> s.getName().contains("a"))
.map(Person::getName)
.collect(Collectors.toList());
aList.forEach(System.out::println); // [결과]: Daol, Jena
}
}
반응형