Java에서 말하는 stream은 2가지로 분류된다.
Stream
운영체제에 의해 생성되는 가상의 연결고리로 실제 데이터의 입력, 출력에 관여하는 매개자의 역할을 한다. 이렇게만 읽으면 무슨 뜻인지 느낌이 오지 않는다. 다른 표현을 빌려본다.
한 번의 읽기 또는 쓰기 동작으로 전송되는 정보
한 장치에서 다른 장치로 보내지는 모든 정보
데이터가 열을 지어 차례대로 입력되는 것
- 입,출력 스트림은 단방향며 입,출력을 동시에 처리할 수 없다.
따라서, 사용목적에 따라 입력스트림, 출력스트림으로 나눌 수 있다. - Java에서는
java.io
package에서 InputStream, OutputStream class를 제공하여 스트림을 다룰 수 있다.(read(), write()) - Java에서 기본적으로 Byte단위로 스트림을 전송하며 FileInputStream, AudioInputStream 등 다양한 class를 제공하고 있다.
Stream API
Stream은 Java 8부터 함수형 프로그래밍을 지원하면서 나온 API이다. 데이터를 추상화하여 재사용성을 높인다.
(데이터를 추상화하였다는 것은 데이터의 종류에 관계없이 같은 방식으로 데이터를 처리할 수 있다는 것을 의미한다.)
배열이나 리스트를 정렬해서 출력하다고하자.
String[] alphabet = {“A”, “D”, “B”, “C”, “E”, “”);
List<String> alphaList = Arrays.asList(alphabet);
// 원본이 변경됨
Arrays.sort(alphabet);
Collections.srot(alphaList);
for(String s : alphabet) {
System.out.println(s);
}
for(String s : alpahList) {
System.out.println(s);
}
Stream API를 사용하지 않으면 보통 이렇게 구성할 것이다.
군더더기 없는 코드이지만 더 깔끔하고 간단하게 만들 수 있다.
String[] alphabet = {“A”, “D”, “B”, “C”, “E”, “”);
List<String> alphaList = Arrays.asList(alphabet);
// 원본은 불변, 별도의 Stream생성
Stream<String> alphaStream = alphabet.stream();
Stream<String> listStream = alphaList.stream();
// 복사된 데이터를 정렬해서 호출
alphaStream.sort().forEach(System.out::println);
listStream.sort().forEach(System.out::println);
Stream API를 적용한다면 이처럼 코드가 간결해지고 가독성이 높아졌다.
Stream API 특징
- 원본 데이터 변경 X
=> Stream API는 원본의 데이터를 조회하여 Stream을 생성한다. 그렇기 때문에 원본에 영향을 주지 않는다.
List<String> list nameList.stream().sorted().collect(Colletors.toList());
- 일회용이다.
=> 이미 사용한 stream을 재사용 불가능하다.
alphaStream.sorted().forEach(System.out::println);
int count = alphaStream.sorted(); // Error
// IllegalStateException
stream has already been operated upon or closed
- 내부적으로 반복을 많이한다.
=> for나 while문 등과 같은 문법들이 내부에 있어 보다 간결한 코드로 작성하는게 가능하다.
listStream.sort().forEach(System.out::println);
- 병렬처리가 가능하다.(Java는 ForkJoinPool Framework를 이용해서 병렬처리를 한다.)
List<String> list = {“a”, “f”, “c”, “q”, “e”};
list.parallelStream().forEach(s-> System.out.println(Thread.currentThread().getName + “: ” + s));
// 결과(당연히 run할 때마다 다름)
ForkJoinPool.commonPool-worker-1: f
ForkJoinPool.commonPool-worker-2: e
ForkJoinPool.commonPool-worker-1: q
main: c
ForkJoinPool.commonPool-worker-3: a
or
stream.parallel().forEach(System.out::println);
//
Stream연산의 종류
Stream 연산은 크게 생성, 가공, 결과 이 세 가지로 나눠진다.
- 생성: Stream 객체를 생성한다.
- 가공: 별도의 데이터로 가공하기 위한 중간 연산이다.(맵핑, 필터링, 정렬 등)
Stream을 반환 하고 필요한 만큼 연결해서 쓸 수 있다. - 결과: 가공된 데이터로부터 원하는 데이터를 위한 최종 연산(반복, 카운트, 총합, 평균, 수집, 그룹핑 등)
Stream요소들을 소모하면서 연산이 시행되기 때문에 한 번만 처리가능하다.
alphaList
.stream() // 생성
.filter( x -> x>2) // 가공
.map(String::toUpperCase) // 가공
.sorted() // 가공
.count(); // 결과
https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html
https://khj93.tistory.com/entry/JAVA-람다식Rambda란-무엇이고-사용법
https://mangkyu.tistory.com/112
https://mangkyu.tistory.com/114
https://ict-nroo.tistory.com/43
http://tcpschool.com/java/java_io_stream
http://tcpschool.com/java/java_stream_concept
'Backend > Java' 카테고리의 다른 글
Generics (0) | 2021.04.27 |
---|---|
Java 버전별 특징 (0) | 2021.04.27 |
Optional (0) | 2021.04.27 |
Thread 생성방식과 동작원리 (0) | 2021.04.23 |
String, StringBuilder, StringBuffer (0) | 2021.04.21 |