Stream API是一种基于流(stream)的API,它提供了一种简洁而高效的处理集合和数组的方法。使用Stream API可以将集合和数组中的数据进行过滤、转换和聚合等操作,同时避免了使用传统的for循环或迭代器的冗长代码.
kotlin 可参考Kotlin Collection KTX:让你的集合操作如丝般顺滑
为什么使用stream API
- java 开发中想要使用kotlin 的集合操作方式,可以使用它。
- 简洁高效:Stream API提供了一种简洁而高效的处理集合和数组的方法,代码更加简洁易读,同时也提高了执行效率。
- 并行处理:Stream API可以实现并行处理,将数据集分成多个块,并且每个块可以在不同的线程中进行处理,从而加快处理速度。
- 延迟执行:Stream API中的操作是延迟执行的,只有在需要返回结果时才会执行,这样可以减少不必要的计算,提高效率。
- 可组合性:Stream API中的多个操作可以组合在一起使用,形成一个完整的处理流程,可以减少中间变量的使用,从而使代码更加简洁。
常用API介绍
- filter(Predicate predicate) 对流中的元素进行筛选,只保留符合条件的元素。
- map(Function<T, R> mapper) 对流中的元素进行映射操作,将每个元素映射成一个新的元素。
- flatMap(Function<T,
Stream<R>> mapper
) 对流中的每个元素进行映射操作,将每个元素映射成一个新的流,并将多个流合并成一个流。 - distinct() 去除流中的重复元素。
- sorted() 对流中的元素进行排序操作。
- limit(long maxSize) 对流进行截取操作,只保留前n个元素。
- skip(long n) 对流进行跳过操作,跳过前n个元素。
- forEach(Consumer action) 对流中的每个元素执行指定的操作。
- reduce(T identity, BinaryOperator accumulator) 对流中的元素进行累加操作,并返回累加结果。
- collect(Collector<T, A, R> collector) 将流中的元素收集成一个集合或其他数据结构。
- anyMatch(Predicate predicate) 判断流中是否有任意一个元素符合指定条件。
- allMatch(Predicate predicate) 判断流中是否所有元素都符合指定条件。
- noneMatch(Predicate predicate) 判断流中是否没有任何一个元素符合指定条件。
- findFirst() 返回流中的第一个元素。
- findAny() 返回流中的任意一个元素。
- count() 返回流中元素的总数。
- max(Comparator comparator) 返回流中的最大值。
- min(Comparator comparator) 返回流中的最小值。
- reduce(BinaryOperator accumulator) 对流中的元素进行累加操作,并返回累加结果。
- toArray(IntFunction<T[]> generator) 将流中的元素转换成一个数组。
此外,Java Stream API还提供了一些中间操作,比如peek()和sorted()等,这些操作可以在Stream中进行链式调用。其中,peek()方法可以用来对Stream中的每个元素执行一些副作用操作
常用API Demo
- filter(Predicate predicate) 过滤集合中符合条件的元素,并返回一个新的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出 [2, 4]
- map(Function<T, R> mapper) 将集合中的每个元素映射成另一个元素,并返回一个新的流
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<Integer> nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println(nameLengths); // 输出 [5, 3, 7]
- flatMap(Function<T, Stream> mapper) 将集合中的每个元素映射成一个流,将所有流中的元素合并成一个新的流
List<List<Integer>> numbers = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6),
Arrays.asList(7, 8, 9)
);
List<Integer> allNumbers = numbers.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(allNumbers); // 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9]
- distinct() 去除流中重复的元素,并返回一个新的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 1, 2, 3);
List<Integer> distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctNumbers); // 输出 [1, 2, 3]
- sorted() 对流中的元素进行排序,并返回一个新的流。
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5);
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNumbers); // 输出 [1, 1, 2, 3, 4, 5, 5, 6, 9]
- limit(long maxSize) 截取流中前面的指定数量元素,并返回一个新的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> limitedNumbers = numbers.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println(limitedNumbers); // 输出 [1, 2, 3]
- skip(long n) 跳过流中前面的指定数量元素,并返回一个新的流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> skippedNumbers = numbers.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println(skippedNumbers); // 输出 [3, 4, 5]
- forEach(Consumer action) 对流中的每个元素执行指定的操作。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.forEach(System.out::println);
// 输出
// Alice
// Bob
// Charlie
- reduce(T identity, BinaryOperator accumulator) 对流中的元素进行累加操作,并返回累加结果。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
System.out.println(sum); // 输出 15
- collect(Collector<T, A, R> collector) 将流中的元素收集成一个集合或其他数据结构。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
String concatenatedNames = names.stream()
.collect(Collectors.joining(", "));
System.out.println(concatenatedNames); // 输出 "Alice, Bob, Charlie"
使用须知
- 需要根据实际情况选择适合的API方法。在使用Java Stream API时,应该根据具体的需求选择适合的API方法。因为Java Stream API提供了很多API方法,不同的API方法适用于不同的场景。
- 确定好中间操作和终端操作。Java Stream API中的操作可以分为中间操作和终端操作。中间操作是指可以在Stream中进行链式调用的操作,例如filter()和map()等;终端操作是指对Stream进行终止操作的操作,例如forEach()和collect()等。在使用Java Stream API时,需要确定好中间操作和终端操作,确保Stream能够正常工作。
- 避免使用过于复杂的操作。尽管Java Stream API提供了很多API方法,但是过于复杂的操作会影响代码的可读性和可维护性。因此,应该避免使用过于复杂的操作。
- 对于大规模数据的处理,建议使用并行流。Java Stream API提供了并行流(parallel stream)的支持,可以将一个Stream分成多个子Stream进行并行处理,提高处理效率。对于大规模数据的处理,建议使用并行流。
文中的APi均为常用型API,具体可以看Stream提供的API与注释。