다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법을 제공
컬렉션, 배열, 가변 매개변수, 지정된 범위의 연속된 정수, 특정 타입의 난수들, 람다 표현식, 파일, 빈 스트림 같은 다양한 데이터 소스에서 Stream API를 생성할 수 있다.
Collection
인터페이스에는 스트림을 생성하는 stream()
이 정의되어 있다.parallelStream()
으로 병렬 처리가 가능한 스트림을 생성할 수도 있다.List<Integer> list = new ArrayList<>(List.of(1, 4, 3, 2));
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
<실행 결과>
1
4
3
2
Stream.forEach()
: 해당 스트림의 요소를 하나씩 소모해가며 순차적으로 접근한다.Arrays
클래스에 다양한 stream()
메서드가 클래스 메서드로 정의되어 있다.String[] array = new String[]{"하나", "넷", "셋", "둘"};
Stream<String> stream1 = Arrays.stream(array);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();
Stream<String> stream2 = Arrays.stream(array, 1, 3);
stream2.forEach(e -> System.out.print(e + " "));
<실행 결과>
하나 넷 셋 둘
넷 셋
Stream
클래스의 of()
→ 가변 매개변수를 전달받아 스트림 생성 가능Stream<Double> stream = Stream.of(4.2, 2.5, 3.1, 1.9)
IntStream
과 LongStream
인터페이스에 range()
, rangeClosed()
가 정의되어 있다.range(int begin, int end)
: begin ~ (end - 1)rangeClosed(int begin, int end)
: begin ~ endIntStream stream1 = IntStream.range(1, 4);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();
IntStream stream2 = IntStream.range(1, 4);
stream2.forEach(e -> System.out.print(e + " "));
<실행 결과>
1 2 3
1 2 3 4
Random
클래스의 ints()
, longs()
, doubles()
Random random = new Random();
IntStream stream = random.ints(4);
stream.forEach(System.out::println);
<실행 결과>
1072176871
-649065206
133298431
-616174137
Stream
클래스의 iterate()
, generate()
iterate()
: seed로 명시된 값을 람다식에 사용하여 반환된 값을 다시 시드로 사용하는 방식generate()
: 매개변수가 없는 람다 표현식을 사용하여 반환된 값으로 무한 스트림 생성IntStream stream = Stream.iterate(2, n -> n + 2); // 2, 4, 6, 8, 10, ..
jva.nio.file.Files
클래스의 lines()
: 파일의 한 행(line)을 요소로 하는 스트림java.nio.BufferedReader
클래스의 lines()
: 파일뿐만 아니라 다른 입력으로부터도 데이터를 행 단위로 읽어올 수 있다.Stream<String> stream = Files.lines(Path path);
Stream<Object> stream = Stream.empty();
System.out.println(stream.count());
<실행 결과>
0
초기 스트림은 중개 연산을 통해 또 다른 스트림으로 변환된다.
연속으로 연결해서 사용할 수 있다.
filter-map 기반 API 사용 → 지연(lazy) 연산을 통해 성능 최적화한다.
filter()
, distinct()
map()
, flatMap()
limit()
, skip()
sorted()
peek()
Stream<T> filter(Predicate<? super T> predicate)
: 주어진 조건(predicate)에 맞는 요소로만 구성된 새로운 스트림 반환Stream<T> distinct()
: 중복된 요소가 제거된 새로운 스트림 반환IntStream stream1 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
IntStream stream2 = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
stream1.distinct()
.forEach(e -> System.out.print(e + " "));
System.out.println();
stream2.filter(n -> n % 2 != 0)
.forEach(e -> System.out.print(e + " "));
<실행 결과>
7 5 2 1 3 4 6
7 5 5 1 3 5
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
: 요소들을 주어진 함수 인수로 전달하여 그 반환값들로 이루어진 새로운 스트림 반환<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
: 스트림의 요소가 배열일 경우 배열의 각 요소의 반환값을 하나로 합친 새로운 스트림 반환Stream<String> stream = Stream.of("HTML", "CSS", "JAVA", "JAVASCRIPT");
stream.map(s -> s.length())
.forEach(System.out::println);
<실행 결과>
4
3
4
10
String[] array = {"Woowahan study", "clean architecture"};
Stream<String> stream = Arrays.stream(array);
stream.flatMap(s -> Stream.of(s.split(" ")))
.forEach(System.out::println);
<실행 결과>
Woowahan
study
clean
architecture
Stream<T> limit(long maxSize)
: 첫 번째 요소부터 전달된 개수만큼의 요소만으로 이루어진 새로운 스트림 반환Stream<T> skip(long n)
: 첫 번째 요소부터 전달된 개수만큼의 요소를 제외한 나머지 요소만으로 이루어진 새로운 스트림 반환IntStream stream1 = IntStream.range(0, 10);
IntStream stream2 = IntStream.range(0, 10);
IntStream stream3 = IntStream.range(0, 10);
stream1.limit(5)
.forEach(n -> System.out.print(n + " "));
System.out.println();
stream1.skip(4)
.forEach(n -> System.out.print(n + " "));
System.out.println();
stream1.skip(3)
.limit(5)
.forEach(n -> System.out.print(n + " "));
<실행 결과>
0 1 2 3 4
4 5 6 7 8 9
3 4 5 6 7
Stream<T> sorted(Comparator<? super T> comparator)
: 주어진 비교자(comparator)를 이용하여 정렬한다.Stream<T>sorted()
: 비교자를 전달하지 않으면 사전 편찬 순(natural order)으로 정렬한다.Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
stream1.sorted()
.forEach(s -> System.out.print(s + " "));
System.out.println();
stream1.sorted(Comparator.reverseOrder())
.forEach(s -> System.out.print(s + " "));
<실행 결과>
CSS HTML JAVA JAVASCRIPT
JAVASCRIPT JAVA HTML CSS
Stream<T> peek(Consumer<? super T> action)
: 원본 스트림이 아닌 결과 스트림으로부터 요소를 소모하여 추가로 명시된 동작을 수행한다.IntStream stream = IntStream.of(7, 5, 5, 2, 1, 2, 3, 5, 4, 6);
stream1.peek(s -> System.out.println("원본 스트림: " + s))
.skip(2)
.peek(s -> System.out.println("skip(2) 실행 후: " + s))
.limit(5)
.peek(s -> System.out.println("limit(5) 실행 후: " + s))
.sorted()
.peek(s -> System.out.println("sorted() 실행 후: " + s))
.forEach(System.out::println);
<실행 결과>
원본 스트림 : 7
원본 스트림 : 5
원본 스트림 : 5
skip(2) 실행 후 : 5
limit(5) 실행 후 : 5
원본 스트림 : 2
skip(2) 실행 후 : 2
limit(5) 실행 후 : 2
원본 스트림 : 1
skip(2) 실행 후 : 1
limit(5) 실행 후 : 1
원본 스트림 : 2
skip(2) 실행 후 : 2
limit(5) 실행 후 : 2
원본 스트림 : 3
skip(2) 실행 후 : 3
limit(5) 실행 후 : 3
sorted() 실행 후 : 1
1
sorted() 실행 후 : 2
2
sorted() 실행 후 : 2
2
sorted() 실행 후 : 3
3
sorted() 실행 후 : 5
5
중개 연산을 통해 변환된 스트림은 최종 연산을 통해 각 요소를 소모하며 결과를 표시한다.
지연(lazy)되었던 모든 중개 연산들이 모두 수행되는 것
최종 연산 시 모든 요소를 소모한 스트림은 더는 사용할 수 없다.
forEach()
reduce()
findFirst()
, findAny()
anyMatch()
, allMatch()
, nonMatch()
count()
, min()
, max()
sum()
, average()
collect()
void forEach(Consumer<? super T> action)
: 각 요소를 소모하여 명시된 동작 수행Stream<String> stream = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
stream..forEach(System.out::println);
<실행 결과>
JAVA
HTML
JAVASCRIPT
CSS
Optional<T> reduce(BinaryOperator<T> accumulator)
: 첫 번째 요소와 두 번째 요소로 연산을 수행한 뒤, 그 결과와 세 번째 요소로 또다시 연산을 수행한다.T reduce(T identity, BinaryOperator<T> accumulator)
: 인수로 전달받은 초기값과 첫 번째 요소와 연산을 한 뒤, 그 결과와 두 번째 요소를 가지고 계속해서 연산을 수행한다.Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Stream<String> stream1 = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
Optional<String> result1 = stream1.reduce(s1, s2) -> s1 + "_" + s2);
result1.ifPresent(System.out::println);
String result2 = stream2.reduce("PYTHON", (s1, s2) -> s1 + "_" + s2);
System.out.println(result2);
<실행 결과>
JAVA_HTML_JAVASCRIPT_CSS
PYTHON_JAVA_HTML_JAVASCRIPT_CSS
Optional<T> findFirst()
, Optional<T> findAny()
: 첫 번째 요소 참조findAny()
를 사용해야 정확한 연산 결과를 얻을 수 있다.IntStream stream1 = IntStream.of(4, 2, 7, 3, 5, 1, 6);
IntStream stream2 = IntStream.of(4, 2, 7, 3, 5, 1, 6);
OptionalInt result1 = stream1.sorted().findFirst();
System.out.println(result1.getAsInt());
OptionalInt result2 = stream2.findAny();
System.out.println(result2.getAsInt());
<실행 결과>
1
4
boolean anyMatch(Predicate<? super T> predicate)
: 특정 조건을 만족하는 요소가 있는가boolean allMatch(Predicate<? super T> predicate)
: 특정 조건을 모두 만족하는가boolean noneMatch(Predicate<? super T> predicate)
: 특정 조건을 모두 만족하지 않는가IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
System.out.println(stream1.anyMatch(n -> n == 70));
System.out.println(stream2.allMatch(n -> n > 80));
<실행 결과>
true
false
long count()
: 요소의 개수 반환Optional<T> max(Comparator<? super T> comparator)
, Optional<T> min(Comparator<? super T> comparator)
: 요소 중 가장 큰 값과 가장 작은 값의 요소를 참조하는 Optional 객체 반환IntStream stream1 = IntStream.of(30, 90, 70, 10);
IntStream stream2 = IntStream.of(30, 90, 70, 10);
long result1 = stream1.count();
OptionalInt result2 = stream2.max();
System.out.println(result1);
System.out.println(result2.getAsInt());
<실행 결과>
4
90
IntStream
, DoubleStream
같은 기본 타입 스트림의 제공 메서드T sum()
: 모든 요소의 합 반환Optional<T> average()
: 모든 요소의 평균값 반환IntStream stream1 = IntStream.of(30, 90, 70, 10);
DoubleStream stream2 = DoubleStream.of(30.3, 90.9, 70.7, 10.1);
int result1 = stream1.sum();
OptionalDouble result2 = stream2.average();
System.out.println(result1);
System.out.println(result2.getAsDouble());
<실행 결과>
200
50.5
<R,A> R collect(Collector<? super T,A,R> collector)
: 인수로 전달되는 Collectors 객체에 구현된 방법대로 스트림의 요소를 수집한다.Collector
클래스에는 미리 정의된 다양한 방법이 정적 메서드로 정의되어 있다.toArray()
toCollection()
toList()
toSet()
toMap()
counting()
maxBy()
minBy()
summingInt()
averagingInt()
reducing()
joining()
groupingBy()
partitioningBy()
Stream<String> stream = Stream.of("JAVA", "HTML", "JAVASCRIPT", "CSS");
List<String> list = stream.collect(Collectors.toList());
Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
System.out.print(iter.next() + " ");
}
<실행 결과>
JAVA HTML JAVASCRIPT CSS
Stream<String> stream = Stream.of("JAVA", "PHP", "JAVASCRIPT", "CSS");
Map<Boolean, List<String>> partition = stream.collect(
Collectors.partitioningBy(s -> s.length() % 2 == 0));
List<String> oddLengthList = partition.get(false);
System.out.println(oddLengthList);
List<String> evenLengthList = partition.get(true);
System.out.println(evenLengthList);
<실행 결과>
[PHP, CSS]
[JAVA, JAVASCRIPT]