데이터 소스가 무엇이든 간에 같은 방식으로 다룰 수 있게 데이터를 추상화 하고 데이터를 다루는데 자주 사용되는 메서드들을 정의해 놓음
특징
스트림은 데이터 소스를 변경하지 않는다.
스트림은 일회용이다. 다시 사용하려면 스트림을 다시 생성
스트림은 작업을 내부 반복으로 처리한다. 반복문을 메서드 내부에 숨길 수 있다는 것을 의미
스트림 예1:
public static void main(String[] args) {
Integer[] nums1={1,2,3,4,5,6,7,8,9,10};
int result1 = Arrays.stream(nums1).mapToInt(x -> x*x).filter(x ->x%2 ==1).sum();
System.out.println(result1);
}
// 터미널 결과:
// 165
결과해석: 1+33+55+77+99 =165
( 중요: 최종연산 sum을 먼저, 지연연산순서대로, 중간 연산들의 순서에 따라 최적화된 처리를 자동으로 수행하지는 않습니다. )
toArray 예2:
package exam01_1;
import java.util.Arrays;
public class Ex01 {
public static void main(String[] args) {
int[] nums = {22, 11, 10, 2, 6,8, 33};
// 배열 임
Arrays.stream(nums).filter(x->x%2 ==1).map(x -> x*x).forEach(System.out::println);
//먼저, nums 배열을 스트림으로 변환합니다.
// 그런 다음, 스트림의 각 요소를 필터링하여 홀수만 선택합니다.
// 선택된 홀수들을 제곱하여 매핑합니다.
// 각 제곱된 홀수를 출력합니다.
//결과: 121 1089 ( 11과 33의 제곱)
//
int[] nums2 = Arrays.stream(nums).map(x -> x * x).filter(x -> x%2 == 1).toArray();
System.out.println(Arrays.toString(nums2));
//먼저, nums 배열을 스트림으로 변환합니다.
// 각 요소를 제곱하여 매핑합니다.
// 매핑된 결과 중에서 홀수만 선택합니다.
// 선택된 홀수들을 새로운 배열로 변환합니다.
// 이 새로운 배열을 출력합니다.
// 결과: [121, 1089]
}
}
mapToInt()
IntStream mapToInt(ToIntFunction<? super T> mapper) :
은 스트림의 각 요소를 int 형식으로 매핑하는 메서드입니다. 여기서 T는 스트림의 요소 유형을 나타냅니다.
package exam01_1;
// 여기 예제가 있습니다. 이 예제는 문자열 배열을 가지고 각 문자열의 길이를 int로 매핑하여 출력합니다.
//
// java
// 코드 복사
import java.util.Arrays;
import java.util.stream.IntStream;
public class Ex02 {
public static void main(String[] args) {
String[] strings = {"apple", "banana", "orange"};
// 문자열 배열을 가지고 IntStream을 생성하고 각 문자열의 길이를 int로 매핑합니다.
IntStream lengthsStream = Arrays.stream(strings).mapToInt(String::length);
// 각 문자열의 길이를 출력합니다.
lengthsStream.forEach(System.out::println);
}
}
//결과:
5
6
6
String::length 이 ToIntFunction<? super T>에 해당!
.
String::length은 String 클래스의 length() 메소드를 참조하는 것입니다.
.
String::length은 ToIntFunction의 applyAsInt 메소드와 시그니처가 일치하므로, 해당 메소드 참조가 ToIntFunction을 나타냅니다.
.
연산을 지연하는 것은 스트림 API의 핵심적인 장점 중 하나입니다. 이는 다음과 같은 이점을 제공합니다:
게으른 계산(Lazy Evaluation): 연산을 지연하면 실제로 필요한 시점에만 연산이 수행됩니다. 이는 메모리와 처리 성능을 절약할 수 있습니다. 예를 들어, 대용량 데이터셋에 대해 여러 연산을 수행할 때, 필요한 결과가 나올 때까지 연산을 미룰 수 있습니다.
스트림은 기본적으로 지연 연산을 사용합니다. 이는 스트림의 특성 중 하나이며, 많은 연산이 게으른 계산 방식으로 작동합니다. 그러나 몇 가지 연산은 즉시 실행되기도 합니다. 예를 들어, collect() 메서드는 최종 연산으로써 스트림의 모든 요소를 수집하여 다른 데이터 구조로 변환하므로 즉시 실행됩니다. 또한 forEach() 메서드는 각 요소에 대해 주어진 동작을 즉시 수행합니다.
단계적인 처리(Step-by-Step Processing): 연산을 지연하면 각 단계의 결과를 중간 스트림으로 얻을 수 있습니다. 이는 중간 결과를 다른 연산에 활용하거나 중간 결과를 조작하여 최종 결과를 도출할 수 있습니다.
최적화(Optimization): 지연된 연산은 최적화에 유리합니다. 예를 들어, 필터링 연산을 수행할 때, 필요한 요소만 처리하여 불필요한 계산을 줄일 수 있습니다.
따라서 연산을 지연하면 자원을 효율적으로 활용하고, 복잡한 데이터 처리 과정을 보다 단순하게 표현할 수 있습니다.
빈 스트림
요소가 하나도 없는 비어있는 스트림
스트림에서 연산을 수행한 결과가 하나도 없을 때, null 보다 빈 스트림을 반환하는 것이 좋다.
스트림에서 null 값을 0으로 처리하는 이유는 주로 다음과 같습니다:
연산의 안정성: null 값이 연산에 포함될 경우 예외가 발생할 수 있습니다. 예를 들어, null 값을 포함한 배열에서 합계를 계산하려고 하면 NullPointerException이 발생할 수 있습니다. null을 0으로 처리하면 이러한 예외를 방지할 수 있습니다.
리듀싱 - reduce()
스트림의 요소를 줄여나가면서 연산을 수행하고 최종결과를 반환한다.
매개변수의 타입은 BinaryOperator이다.
처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소를 연산한다.
day19/StreamEx5.java
package day19;
import java.util.*;
import java.util.stream.*;
public class StreamEx5 {
public static void main(String[] args) {
String[] strArr = {
"Inheritance", "Java", "Lambda", "stream",
"optionalDouble", "IntStream", "count", "sum"
};
Stream.of(strArr).forEach(System.out::println);
// Stream.of(strArr)를 사용하여 문자열 배열을 스트림으로 변환하고, forEach를 사용하여 각 요소를 출력합니다.
boolean noEmptyStr = Stream.of(strArr).noneMatch(s->s.length() == 0);
Optional<String> sWord = Stream.of(strArr)
.filter(s->s.charAt(0) == 's').findFirst();
//findFirst를 사용하여 배열에서 's'로 시작하는 첫 번째 단어를 찾습니다.
System.out.println("noEmptyStr=" + noEmptyStr);
System.out.println("sWord=" + sWord.get());
// Stream<String[]>을 IntStream으로 변환
IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);
//mapToInt를 사용하여 각 문자열의 길이를 IntStream으로 변환합니다.
int count = intStream1.reduce(0, (a,b) -> a + 1);
//intStream1은 문자열 배열의 각 문자열의 길이를 담고 있는 IntStream입니다.
reduce 메서드는 스트림의 요소를 줄여 하나의 결과값을 생성합니다.
초기값으로 0을 설정하고, 각 요소를 방문할 때마다 a + 1 연산을 수행합니다.
여기서 a는 누적값이고, b는 현재 요소의 값입니다.
이 코드는 각 요소를 방문할 때마다 누적값에 1을 더하여 요소의 개수를 계산합니다. 결과적으로 count 변수에는 요소의 개수가 저장됩니다.
int sum = intStream2.reduce(0, (a,b) -> a + b);
//intStream2는 문자열 배열의 각 문자열의 길이를 담고 있는 IntStream입니다.
초기값으로 0을 설정하고, 각 요소를 방문할 때마다 a + b 연산을 수행합니다.
여기서 a는 누적값이고, b는 현재 요소의 값입니다(즉, 문자열의 길이).
이 코드는 각 요소의 길이를 누적하여 모두 더한 값을 계산합니다. 결과적으로 sum 변수에는 모든 문자열의 길이의 합이 저장됩니다.
OptionalInt max = intStream3.reduce(Integer::max);
OptionalInt min = intStream4.reduce(Integer::min);
//reduce를 사용하여 각 IntStream에 대해 다양한 연산을 수행합니다.
System.out.println("count=" + count);
System.out.println("sum=" + sum);
System.out.println("max=" + max.getAsInt());
System.out.println("min=" + min.getAsInt());
}
}
결과:
Inheritance
Java
Lambda
stream
optionalDouble
IntStream
count
sum
noEmptyStr=true
sWord=stream
count=8
sum=58
max=14
min=3
스트림 stream
스트림
특징
스트림 예1:
결과해석: 1+33+55+77+99 =165 ( 중요: 최종연산 sum을 먼저, 지연연산순서대로, 중간 연산들의 순서에 따라 최적화된 처리를 자동으로 수행하지는 않습니다. )
toArray 예2:
mapToInt()
String::length 이 ToIntFunction<? super T>에 해당! . String::length은 String 클래스의 length() 메소드를 참조하는 것입니다. . String::length은 ToIntFunction의 applyAsInt 메소드와 시그니처가 일치하므로, 해당 메소드 참조가 ToIntFunction을 나타냅니다.
.
연산을 지연의 장점
연산을 지연하는 것은 스트림 API의 핵심적인 장점 중 하나입니다. 이는 다음과 같은 이점을 제공합니다:
스트림은 기본적으로 지연 연산을 사용합니다. 이는 스트림의 특성 중 하나이며, 많은 연산이 게으른 계산 방식으로 작동합니다. 그러나 몇 가지 연산은 즉시 실행되기도 합니다. 예를 들어,
collect()
메서드는 최종 연산으로써 스트림의 모든 요소를 수집하여 다른 데이터 구조로 변환하므로 즉시 실행됩니다. 또한forEach()
메서드는 각 요소에 대해 주어진 동작을 즉시 수행합니다.단계적인 처리(Step-by-Step Processing): 연산을 지연하면 각 단계의 결과를 중간 스트림으로 얻을 수 있습니다. 이는 중간 결과를 다른 연산에 활용하거나 중간 결과를 조작하여 최종 결과를 도출할 수 있습니다.
최적화(Optimization): 지연된 연산은 최적화에 유리합니다. 예를 들어, 필터링 연산을 수행할 때, 필요한 요소만 처리하여 불필요한 계산을 줄일 수 있습니다.
따라서 연산을 지연하면 자원을 효율적으로 활용하고, 복잡한 데이터 처리 과정을 보다 단순하게 표현할 수 있습니다.
빈 스트림
요소가 하나도 없는 비어있는 스트림 스트림에서 연산을 수행한 결과가 하나도 없을 때, null 보다 빈 스트림을 반환하는 것이 좋다. 스트림에서 null 값을 0으로 처리하는 이유는 주로 다음과 같습니다:
리듀싱 - reduce() 스트림의 요소를 줄여나가면서 연산을 수행하고 최종결과를 반환한다. 매개변수의 타입은 BinaryOperator이다. 처음 두 요소를 가지고 연산한 결과를 가지고 그 다음 요소를 연산한다.