目录
1.概述
2.Steam操作
中间操作(Intermediate operations)
(1)filter
(2)map
(3)flatMap
(4)sorted
(5)peek
(6) limit
(7) skip
(8)distinct
终端操作(Terminal operations)
(1)forEach
(2) collect
(3) reduce
(4)toArray
(5)min
(6)max
(7)count
(8)anyMatch
(9)allMatch
(10)noneMatch
(11)findFirst
(12)findAny
3.创建 Stream
(1) stream
(2) Arrays.stream
(3) Stream.of
(4) Stream.iterate
4.并行 Streams
(1)parallelStream
(2)parallel
5.Collectors
(1)toList
(2)toSet
(3)toMap
(4)joining
(5)counting
6.使用 Stream 的注意事项
1. 概述
Java Stream API 是 Java 8 及以上版本中提供的一种新特性,它支持对集合(Collections)进行声明式的操作。Stream API 可以用于执行复杂的数据转换操作,并支持并行处理。
2. Steam操作
中间操作(Intermediate operations)
中间操作返回的是一个新的 Stream
,可以继续进行链式调用。以下是一些常见的中间操作:
(1)filter
filter(Predicate<? super T> predicate)
: 过滤元素。 示例: 过滤出列表中所有偶数。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); List<Integer> evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(evenNumbers); // 输出 [2, 4, 6]
(2)map
map(Function<? super T, ? extends R> mapper)
: 转换每个元素到对应的结果。 示例: 将每个字符串转换为大写。
List<String> words = Arrays.asList("hello", "world"); List<String> upperCaseWords = words.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(upperCaseWords); // 输出 [HELLO, WORLD]
(3)flatMap
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
: 将每个元素转换成另一个 Stream
,然后将所有流连接成一个流。 示例:将包含单词列表的列表转换为单词流。
List<List<String>> listOfLists = Arrays.asList( Arrays.asList("hello", "world"), Arrays.asList("goodbye", "world") ); List<String> words = listOfLists.stream() .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(words); // 输出 [hello, world, goodbye, world]
(4)sorted
sorted()
: 对元素进行自然排序。 示例:对整数列表进行自然排序。
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9); List<Integer> sortedNumbers = numbers.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNumbers); // 输出 [1, 1, 3, 4, 5, 9]
sorted(Comparator<? super T> comparator)
: 使用提供的比较器对元素进行排序。 示例:使用自定义比较器对字符串列表进行排序。
List<String> words = Arrays.asList("banana", "apple", "cherry"); List<String> sortedWords = words.stream() .sorted(Comparator.reverseOrder()) .collect(Collectors.toList()); System.out.println(sortedWords); // 输出 [cherry, banana, apple]
(5)peek
peek(Consumer<? super T> action)
: 用于调试,允许你无修改地查看流中的元素。 示例:打印每个元素,用于调试。
List<String> words = Arrays.asList("hello", "world"); List<String> upperCaseWords = words.stream() .peek(System.out::println) // 打印每个元素 .map(String::toUpperCase) .collect(Collectors.toList());
(6) limit
limit(long maxSize)
: 限制流的大小。 示例:限制流的大小。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); List<Integer> limitedNumbers = numbers.stream() .limit(3) .collect(Collectors.toList()); System.out.println(limitedNumbers); // 输出 [1, 2, 3]
(7) skip
skip(long n)
: 跳过流中的前 n 个元素。 示例:跳过列表中的前 n 个元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); List<Integer> skippedNumbers = numbers.stream() .skip(3) .collect(Collectors.toList()); System.out.println(skippedNumbers); // 输出 [4, 5, 6, 7, 8, 9]
(8)distinct
distinct()
: 去除重复元素。 示例:
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5, 5, 5, 6); List<Integer> distinctNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); System.out.println(distinctNumbers); // 输出 [1, 2, 3, 4, 5, 6]
终端操作(Terminal operations)
终端操作返回的是一个结果或一个副作用(例如打印结果),之后不能再对 Stream
进行操作。以下是一些常见的终端操作:
(1)forEach
forEach(Consumer<? super T> action)
: 对每个元素执行一个操作。 示例:对每个元素执行打印操作。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:打印每个元素 words.stream().forEach(System.out::println); // apple // banana // cherry
(2) collect
collect(Collector<? super T, A, R> collector)
: 将流转换为其他形式,如列表、集合或 Map。 示例:将流转换为列表。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:将流转换为列表 [APPLE, BANANA, CHERRY] List<String> upperCaseWords = words.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(upperCaseWords);
(3) reduce
reduce(T identity, BinaryOperator<T> accumulator)
: 通过一个起始值,反复利用 BinaryOperator 来处理和累积元素,返回一个值。 示例:使用 Integer::sum
作为累加器,将流中的整数相加。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 预期结果:计算总和 15 int sum = numbers.stream().reduce(0, Integer::sum); System.out.println(sum); // 15
reduce(BinaryOperator<T> accumulator)
: 使用一个 BinaryOperator 来累积元素,返回一个 Optional。 示例: 使用 Integer::max
作为累加器,找到流中的最大值。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 预期结果:找到最大值 5 Optional<Integer> max = numbers.stream().reduce(Integer::max); max.ifPresent(System.out::println); // 5
(4)toArray
toArray()
: 将流转换为对象数组。 示例:使用 toArray
方法将流转换为对象数组。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:将流转换为对象数组 [apple, banana, cherry] Object[] wordArray = words.stream().toArray(); System.out.println(Arrays.toString(wordArray));
toArray(IntFunction<A[]> generator)
: 将流转换为特定类型的数组。 示例:使用 toArray
方法将流转换为特定类型的数组。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:将流转换为字符串数组 [apple, banana, cherry] String[] wordArray = words.stream().toArray(String[]::new); System.out.println(Arrays.toString(wordArray));
(5)min
min(Comparator<? super T> comparator)
: 找到最小元素。 示例:使用 min
方法找到流中的最小元素。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:找到最小元素 apple Optional<String> min = words.stream().min(String::compareTo); min.ifPresent(System.out::println); // apple
(6)max
max(Comparator<? super T> comparator)
: 找到最大元素。 示例:使用 max
方法找到流中的最大元素。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:找到最大元素 cherry Optional<String> max = words.stream().max(String::compareTo); max.ifPresent(System.out::println); // cherry
(7)count
count()
: 返回流中元素的数量。 示例:使用 count
方法返回流中元素的数量。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:流中元素的数量 3 long count = words.stream().count(); System.out.println(count); // 3
(8)anyMatch
anyMatch(Predicate<? super T> predicate)
: 检查是否至少有一个元素匹配给定的谓词。 示例: 这个方法用于检查流中是否至少有一个元素匹配给定的谓词。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:至少有一个元素以 "a" 开头 boolean anyMatch = words.stream().anyMatch(s -> s.startsWith("a")); System.out.println(anyMatch); // 输出 true
(9)allMatch
allMatch(Predicate<? super T> predicate)
: 检查是否所有元素都匹配给定的谓词。 示例:这个方法用于检查流中是否所有元素都匹配给定的谓词。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:所有元素都以 "c" 开头 boolean allMatch = words.stream().allMatch(s -> s.startsWith("c")); System.out.println(allMatch); // 输出 false
(10)noneMatch
noneMatch(Predicate<? super T> predicate)
: 检查是否没有元素匹配给定的谓词。 示例: 这个方法用于检查流中是否没有元素匹配给定的谓词。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:没有元素以 "z" 开头 boolean noneMatch = words.stream().noneMatch(s -> s.startsWith("z")); System.out.println(noneMatch); // 输出 true
(11)findFirst
findFirst()
: 返回第一个元素。 示例:这个方法用于返回流中的第一个元素。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:返回第一个元素 "apple" Optional<String> first = words.stream().findFirst(); first.ifPresent(System.out::println); // apple
(12)findAny
findAny()
: 返回任意一个元素(在并行流中特别有用)。 示例:这个方法用于返回流中的任意一个元素。
List<String> words = Arrays.asList("apple", "banana", "cherry"); // 预期结果:返回任意一个元素,可能是 "apple", "banana" 或 "cherry" Optional<String> any = words.stream().findAny(); any.ifPresent(System.out::println); // 输出一个随机的字符串元素
3. 创建 Stream
创建 Stream
的方式有很多:
(1) stream
通过集合的 stream()
方法。 示例:
List<String> list = Arrays.asList("apple", "banana", "cherry"); Stream<String> stream = list.stream();
(2) Arrays.stream
通过数组的 Arrays.stream(Object[])
方法。 示例:
String[] array = {"apple", "banana", "cherry"}; Stream<String> stream = Arrays.stream(array);
(3) Stream.of
使用 Stream.of(T... values)
静态方法。 示例:
Stream<String> stream = Stream.of("apple", "banana", "cherry");
(4) Stream.iterate
使用 Stream.iterate(T seed, UnaryOperator<T> f)
或 Stream.generate(Supplier<T> s)
创建无限流。 // 使用 Stream.iterate 创建无限流 Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1); // 使用 Stream.generate 创建无限流 Stream<String> generateStream = Stream.generate(() -> "hello");
4. 并行 Streams
Stream
接口还有一个子接口 BaseStream
和一个并行流接口 ParallelStream
,用于并行处理数据。
并行流可以提高处理大量数据时的性能,因为它可以利用多核处理器的能力来并行地执行操作。但是,并不是所有的流操作都适合并行处理,你需要根据具体的情况来决定是否使用并行流
(1)parallelStream
parallelStream()
方法,该方法是 Stream
接口的一个扩展方法。 示例:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); // 创建并行流 List<Integer> evenNumbers = numbers.parallelStream() .filter(n -> n % 2 == 0) .collect(Collectors.toList()); System.out.println(evenNumbers); // 输出 [2, 4, 6, 8]
(2)parallel
parallel()
方法,该方法是 BaseStream
接口的一个扩展方法。 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); // 使用 parallel() 方法创建并行流 List<Integer> evenNumbers = numbers.stream() .parallel() // 创建并行流 .filter(n -> n % 2 == 0) // 过滤偶数 .collect(Collectors.toList()); // 收集结果 System.out.println(evenNumbers); // 输出 [2, 4, 6, 8]
5. Collectors
Collectors
类提供了很多静态方法,用于实现常见的归约操作,如将元素累积到集合、字符串、Map 等。
(1)toList
toList()
: 将流中的元素收集到列表中。
示例:
List<String> words = Arrays.asList("apple", "banana", "cherry"); List<String> collectedWords = words.stream().collect(Collectors.toList()); System.out.println(collectedWords); // 输出 [apple, banana, cherry]
(2)toSet
toSet()
: 将流中的元素收集到集合中,自动去除重复项。 示例:
List<String> words = Arrays.asList("apple", "banana", "cherry", "apple", "banana"); Set<String> collectedWords = words.stream().collect(Collectors.toSet()); System.out.println(collectedWords); // 输出 [apple, banana, cherry]
(3)toMap
toMap()
: 将流中的元素收集到 Map 中,其中流中的元素作为键或值。 示例:
List<String> words = Arrays.asList("apple", "banana", "cherry"); Map<String, Integer> wordCount = words.stream().collect(Collectors.toMap( word -> word, word -> word.length() )); System.out.println(wordCount); // 输出 {apple=5, banana=6, cherry=6}
(4)joining
joining()
: 将流中的元素连接成一个字符串。 示例:
List<String> words = Arrays.asList("apple", "banana", "cherry"); String joinedString = words.stream().collect(Collectors.joining("-")); System.out.println(joinedString); // 输出 apple-banana-cherry
(5)counting
counting()
: 计算流中元素的数量。 示例:
List<String> words = Arrays.asList("apple", "banana", "cherry"); long wordCount = words.stream().collect(Collectors.counting()); System.out.println(wordCount); // 输出 3
6. 使用 Stream 的注意事项
流一旦执行终端操作,就会被消耗掉,不可以再使用该流执行其他操作。流操作不会改变原始数据源,所有的操作都会返回一个新的Stream
对象。流操作可以并行化,但需要注意线程安全和数据竞争问题。