종류 | 내용 |
---|---|
Stream <T> | 범용 Stream |
IntStream | 값 타입이 Int인 Stream |
LongStream | 값 타입이 Long인 Stream |
DoubleStream | 값 타입이 Double인 Stream |
String[] arr = new String[]{"a","b","c"};
Stream<String> stream = Arrays.stream(arr);
Stream<String> streamOfArrayPart = Arrays.stream(arr,1,3); // [1]~[2] 요소를 의미 : [b,c]
List<String> list = Array.asList("a","b","c");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream(); // 병렬 처리가 가능한 stream 객체
public Stream<String> streamOf(List<String> list) {
return list == null || list.isEmpty() ? Stream.empty() : list.stream();
}
Stream<String> builderStream =
Stream.<String>builder()
.add("a").add("b").add("c")
.build(); // builderStream는 ["a", "b", "c"] 이다.
Supplier<T>
에 해당하는 람다로 값을 넣을 수 있다. Stream<String> generatedStream =
Stream.genertate(() -> "a").limit(5);
// ["a","a","a","a","a"]
() -> "a"
부분이 Supplier<T>
에 해당한다.Stream<Integer> iteratedStream =
Stream.iterate(30, n -> n+2).limit(5);
// [30,32,34,36,38]
IntStream intStream = IntStream.range(1,5); // [1,2,3,4]
LongStream longStream = LongStream.rangeClosed(1,5); // [1,2,3,4,5]
range
: 마지막 인덱스를 포함하지 않는다.rangeClosed
: 마지막 인덱스를 포함한다.DoubleStream doubles = new Random().doubles(3);
// double형 난수 3개를 가진 스트림을 생성한다.
Random
클래스는 난수를 가지고 3가지 타입의 스트림을 생성한다.IntStream charsStream = "Stream".chars();
// [83, 116, 114, 101, 97, 109]
Stream<String> stringPattern =
Pattern.compile(", ").splitAsStream("A, B, C");
// ["A","B","C"]
Stream<String> lineStream =
Files.lines(Paths.get("file.txt"), Charset.forName("UTF-8"));
parallelStream
메소드로 병렬 Stream 생성stream
메소드 대신 parallelStream
메소드를 사용하여 병렬 스트림을 생성할 수 있다.// 병렬 스트림 생성
Stream<Product> parallelStream = productList.parallelStream();
// 병렬 여부 확인하기
boolean isParallel = parallelStream.isParallel();
boolean isMany = parallelStream
.map(product -> product.getAmount()*10)
.anyMatch(amount -> amount > 200);
Arrays.stream(arr).parallel();
parallel
메소드를 이용하여 병렬 스트림을 생성할 수 있다.IntStream intStream = IntStream.range(1,150).parallel();
boolean isParallel = intStream.isParallel();
sequential
메소드를 활용하면 쓰레드를 이용한 병렬 처리가 불가능하다IntStream intStream = intStream.sequential();
boolean isParallel = intStream.isParallel();
Stream.concat
메소드로 두개의 스트림을 연결하여 새로운 하나의 스트림을 만들 수 있다.Stream<String> stream1 = Stream.of("Java", "Scala", "Groovy");
Stream<String> stream2 = Stream.of("Python", "Go", "Swift");
Stream<String> concat = Stream.concat(stream1, stream2);
// [Java, Scala, Groovy, Python, Go, Swift]
필터링, 맴핑 등의 중간 작업을 통해 스트림 가공하기
API를 사용하여 원하는 데이터만 뽑는 작업을 중간작업
이라고 한다.
중간 작업
은 중간 연산 명령어를 활용한다.이 작업은 스트림을 리턴하므로 chaining
이 가능하다.
기본 리스트
List<String> names = Arrays.asList("Eric", "Elena", "Java");
Predicate
는 boolean을 리턴하는 함수형 인터페이스 형태이다.Stream<T> filter(Predicate<? super T> predicate);
names
리스트의 데이터중 "a"문자를 포함하는 데이터로만 이뤄진 스트림 생성하기Stream<String> stream =
names.stream()
.filter(name -> name.contains("a");
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
Stream<Integer> stream =
productList.stream()
.map(String::toUpperCase);
// [ERIC, ELENA, JAVA]
Stream<Integer> stream =
productList.stream()
.map(Product::getAmount);
// [23, 14, 13, 23, 13]
flatMap
메소드는 리턴타입이 Stream이다.flatMap
메소드는 중첩 구조를 한단계 제거하고 단일 컬렉션으로 만들어준다.[[a],[b]]
to [a, b]
List<List<String>> list =
Arrays.asList(Arrays.asList("a"),
Arrays.asList("b"));
// [[a],[b]] <- 중첩된 구조
flatMap
메소드를 활용하여 중첩 리스트 구조를 제거한 뒤 작업할 수 있다.List<String> flatList =
list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
// [a, b] <- 중첩구조가 제거됨
students.stream()
.flatMapToInt(student ->
IntStream.of(student.getKor(),
student.getEng(),
student.getMath())) // 국,영,수 점수를 뽑아내어
.average().ifPresent(avg ->
System.out.println(Math.round(avg * 10)/10.0)); // 평균을 구한다.
map
메소드 만으로 한번에 할 수 없는 기능을 flatMap
메소드는 가능케 한다.Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);
IntStream.of(14, 11, 20, 39, 23)
.sorted()
.boxed()
.collect(Collectors.toList());
// [11, 14, 20, 23, 39]
List<String> lang =
Arrays.asList("Java", "Scala", "Groovy", "Python", "Go", "Swift");
lang.stream()
.sorted() // 단순히 오름차순 정렬
.collect(Collectors.toList());
// [Go, Groovy, Java, Python, Scala, Swift]
lang.stream()
.sorted(Comparator.reverseOrder()) // 내림차순 정렬
.collect(Collectors.toList());
// [Swift, Scala, Python, Java, Groovy, Go]
compare
메소드 활용하기int compare(T o1, T o2)
lang.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
// [Go, Java, Scala, Swift, Groovy, Python]
lang.stream()
.sorted((s1, s2) -> s2.length() - s1.length()) // int compare(T o1, T o2) 메소드 활용
.collect(Collectors.toList());
// [Groovy, Python, Scala, Swift, Java, Go]
peek
메소드 : 스트림 내의 요소들을 그냥 확인만 하는 메소드이다.Stream<T> peek(Consumer<? super T> action);
int sum = IntStream.of(1, 3, 5, 7, 9)
.peek(System.out::println)
.sum();
long count = IntStream.of(1, 3, 5, 7, 9).count();
long sum = LongStream.of(1, 3, 5, 7, 9).sum();
count
, sum
의 결과는 0이 된다.OptionalInt min = IntStream.of(1, 3, 5, 7, 9).min();
OptionalInt max = IntStream.of(1, 3, 5, 7, 9).max();
Optional<T>
클래스는 null 이 올 수 있는 값을 감싸는 래퍼 클래스로 참조하더라도 null 이 일어나지 않도록 해주는 클래스이다.ifPresent
메소드를 이용해서 Optional 을 처리할 수 있다DoubleStream.of(1.1, 2.2, 3.3, 4.4, 5.5)
.average()
.ifPresent(System.out::println);
reduce
메소드 : 스트림은 이 메소드를 이용하여 결과를 만들어낸다.// 1개 (accumulator)
Optional<T> reduce(BinaryOperator<T> accumulator);
// 2개 (identity)
T reduce(T identity, BinaryOperator<T> accumulator);
// 3개 (combiner)
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
reduce
메소드는 3가지 파라미터를 받을 수 있다.Optional<T> reduce(BinaryOperator<T> accumulator);
BinaryOperator<T>
: 같은 타입의 인자 두개를 받아 같은 타입의 결과를 반환하는 함수형 인터페이스이다.OptionalInt reduced =
IntStream.range(1, 4) // [1, 2, 3]
.reduce((a, b) -> {
return Integer.sum(a, b);
});
// 결과는 1+2+3 = 6이 된다.
T reduce(T identity, BinaryOperator<T> accumulator);
int reducedTwoParams =
IntStream.range(1, 4) // [1, 2, 3]
.reduce(10, Integer::sum);
// 결과는 10 + 1+ 2 +3 = 16 이 된다.
// 10은 초기값이다.
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
Integer reducedParams = Stream.of(1, 2, 3)
.reduce(10, // identity
Integer::sum, // accumulator
(a, b) -> {
System.out.println("combiner was called"); // combiner는 실행되지 않는다
return a + b;
});
Integer reducedParallel = Arrays.asList(1, 2, 3)
.parallelStream()
.reduce(10, // identity
Integer::sum, // accumulator
(a, b) -> {
System.out.println("combiner was called");
return a + b;
});
// 결과
combiner was called
combiner was called
36
collect
메소드 : 또다른 종료 작업Collector
타입의 인자를 받아서 처리한다.List<Product> productList =
Arrays.asList(new Product(23, "potatoes"),
new Product(14, "orange"),
new Product(13, "lemon"),
new Product(23, "bread"),
new Product(13, "sugar"));
List<String> collectorCollection =
productList.stream()
.map(Product::getName)
.collect(Collectors.toList());
// [potatoes, orange, lemon, bread, sugar]
Collectors.toList()
를 통해 리스트로 결과를 가져온다.String listToString =
productList.stream()
.map(Product::getName)
.collect(Collectors.joining());
// potatoesorangelemonbreadsugar
Collectors.joining()
메소드는 3개의 인자를 받을 수 있다.String listToString =
productList.stream()
.map(Product::getName)
.collect(Collectors.joining(", ", "<", ">"));
// <potatoes, orange, lemon, bread, sugar>
Double averageAmount =
productList.stream()
.collect(Collectors.averagingInt(Product::getAmount));
// 17.2
Integer summingAmount =
productList.stream()
.collect(Collectors.summingInt(Product::getAmount));
// 86
Integer summingAmount =
productList.stream()
.mapToInt(Product::getAmount) // mapToInt 메소드를 사용한 간결한 표현
.sum(); // 86
boolean anyMatch(Predicate<? super T> predicate);
boolean allMatch(Predicate<? super T> predicate);
boolean noneMatch(Predicate<? super T> predicate);
조건식 람다 Predicate 를 받아서 해당 조건을 만족하는 요소가 있는지 체크한 결과를 리턴한다.
예제
List<String> names = Arrays.asList("Eric", "Elena", "Java");
boolean anyMatch = names.stream()
.anyMatch(name -> name.contains("a")); // true
boolean allMatch = names.stream()
.allMatch(name -> name.length() > 3); // true
boolean noneMatch = names.stream()
.noneMatch(name -> name.endsWith("s")); // true
forEach
: 스트림 내 요소를 돌면서 실행되는 최종 작업names.stream().forEach(System.out::println);