结束操作是指结束 Stream 该如何处理的操作,并且会触发 Stream 的执行。下面是一些常用的结束操作方法。结束操作会对数据源进行遍历,因此是及早求值的。
Java8 Stream详解及中间操作方法使用示例(一)
Java8 Stream详解及创建流方法使用示例(二)
- forEach(Consumer<T> action):对流中的每个元素执行指定的操作。
- toArray():将流中的元素转换成数组。
- reduce(T identity, BinaryOperator<T> accumulator):使用指定的累加器对流中的元素进行聚合。
- collect(Collector<T,A,R> collector):将流中的元素收集到一个容器中。
- min(Comparator<T> comparator):返回流中的最小元素。
- max(Comparator<T> comparator):返回流中的最大元素。
- count():返回流中元素的数量。
- anyMatch(Predicate<T> predicate):判断流中是否有任意一个元素匹配指定的条件。
- allMatch(Predicate<T> predicate):判断流中是否所有元素都匹配指定的条件。
- noneMatch(Predicate<T> predicate):判断流中是否没有任何一个元素匹配指定的条件。
- findFirst():返回流中的第一个元素。
- findAny():返回流中的任意一个元素。
Stream结束操作方法 详细示例
forEach(Consumer<? super T> action)
forEach()
方法是Stream
类中的一个最终操作方法,它接收一个Consumer
函数作为参数,用于对流中的每个元素执行指定的操作。forEach()
方法会遍历整个流,并对每个元素执行指定的操作,操作顺序是按照流的顺序执行。例如,假设有一个包含多个字符串的列表,现在需要将每个字符串转换成小写字母并输出,可以使用
forEach()
方法实现:List<String> strList = Arrays.asList("Java", "Stream", "API"); strList.stream() .map(String::toLowerCase) .forEach(System.out::println);
以上代码中,首先从字符串列表中创建一个
Stream
,然后对每个字符串执行String::toLowerCase
方法,即将字符串转换为小写字母,最后通过forEach()
方法对每个元素执行System.out::println
操作,即将元素输出到控制台。需要注意的是,由于
forEach()
方法是一个最终操作方法,因此无法返回任何值。如果需要将流中的元素转换为另一个集合或数组等对象,可以使用collect()
方法。同时,由于forEach()
方法是一个终端操作,因此不能再对同一个流进行连续的操作,需要重新创建一个新的流进行操作。另外,由于
forEach()
方法是一个阻塞操作,因此在处理大量数据时可能会产生性能问题。如果需要并行执行操作以提高处理效率,可以使用forEachOrdered()
方法或parallelStream()
方法。forEachOrdered()
方法与forEach()
方法类似,但它会保证按照原始顺序处理元素;parallelStream()
方法可以将流转换为并行流,在多核处理器上并行执行操作。
forEachOrdered(Consumer<? super T> action)
forEachOrdered()
方法是Stream
类中的一个最终操作方法,它接收一个Consumer
函数作为参数,用于对流中的每个元素执行指定的操作,与forEach()
方法类似。不同之处在于,forEachOrdered()
方法会保证按照流中元素的原始顺序依次执行操作。例如,假设有一个包含多个字符串的列表,现在需要将每个字符串转换成小写字母并输出,输出的顺序要与原始顺序保持一致,可以使用
forEachOrdered()
方法实现:List<String> strList = Arrays.asList("Java", "Stream", "API"); strList.stream() .map(String::toLowerCase) .forEachOrdered(System.out::println);
以上代码中,首先从字符串列表中创建一个
Stream
,然后对每个字符串执行String::toLowerCase
方法,即将字符串转换为小写字母,最后通过forEachOrdered()
方法对每个元素执行System.out::println
操作,即将元素输出到控制台。由于调用了forEachOrdered()
方法,因此输出的顺序与原始顺序保持一致。需要注意的是,由于
forEachOrdered()
方法是一个最终操作方法,因此无法返回任何值。如果需要将流中的元素转换为另一个集合或数组等对象,可以使用collect()
方法。同时,由于forEachOrdered()
方法是一个阻塞操作,因此在处理大量数据时可能会产生性能问题。如果需要并行执行操作以提高处理效率,可以使用parallelStream()
方法。
toArray()
toArray()方法是一个终止操作,用于将Stream对象中的元素转换为数组并返回。该方法不接收任何参数,将返回一个Object类型的数组,可以使用泛型类型推断进行强制类型转换。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用toArray()方法。
- 该方法将Stream对象中的元素转换为一个Object类型的数组,并返回该数组。
例如,以下代码演示了如何使用toArray()方法将字符串流中的元素转换为数组:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear"); Object[] array = list.stream().toArray(); System.out.println(Arrays.toString(array)); // 输出 [apple, banana, orange, pear]
上述代码创建一个String类型的列表,并将其转换成Stream对象。接下来调用toArray()方法,该方法将Stream对象中的元素转换为一个Object类型的数组,并返回该数组。最后使用Arrays.toString()方法将数组转换为字符串形式,并输出到控制台上。
需要注意的是,由于toArray()方法返回一个Object类型的数组,因此需要使用泛型类型推断进行强制类型转换。例如,如果要将String类型的元素转换为String类型的数组,可以使用以下代码:
String[] strArray = list.stream().toArray(String[]::new);
在这里,我们使用了方法引用的形式,将构造函数String[]::new作为参数传递给toArray()方法,以便将Object类型的数组转换为String类型的数组。
toArray(IntFunction<A[]> generator)
toArray(IntFunction<A[]> generator)方法是一个终止操作,用于将Stream对象中的元素转换为一个新的指定类型的数组并返回。该方法接收一个IntFunction函数作为参数,用于创建一个新的、指定大小的数组,以容纳Stream对象中的所有元素。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用toArray(IntFunction<A[]> generator)方法,并传入一个IntFunction函数。
- 该方法将使用IntFunction函数创建一个新的、指定大小的数组,并将Stream对象中的元素转换到该数组中。
例如,以下代码演示了如何使用toArray()方法和Lambda表达式将字符串流中的元素转换为String类型的数组:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear"); String[] strArray = list.stream().toArray(size -> new String[size]); System.out.println(Arrays.toString(strArray)); // 输出 [apple, banana, orange, pear]
上述代码创建一个String类型的列表,并将其转换成Stream对象。接下来调用toArray()方法,并传入一个Lambda表达式,该表达式根据给定的大小创建一个String类型的数组。该方法将使用Lambda表达式创建新的数组,并将Stream对象中的元素转换到该数组中。最后使用Arrays.toString()方法将数组转换为字符串形式,并输出到控制台上。
需要注意的是,由于我们需要创建指定类型的数组,因此需要使用泛型并进行强制类型转换。在上述例子中,我们使用了Lambda表达式(size -> new String[size])创建一个新的String类型的数组。根据size的值,该表达式将返回一个指定大小的、String类型的数组。
reduce(BinaryOperator<T> accumulator)
reduce(BinaryOperator<T> accumulator)方法是一个终止操作,用于将所有元素归约成单个结果。该方法接收一个BinaryOperator函数作为参数,用于对流中的元素执行累加操作。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用reduce(BinaryOperator<T> accumulator)方法,并传入一个BinaryOperator函数。
- 该方法将在整个流上执行指定的累加操作,并返回包含结果的Optional对象。
例如,以下代码演示了如何使用reduce()方法计算整数列表中所有元素的和:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> result = list.stream().reduce((a, b) -> a + b); result.ifPresent(System.out::println); // 输出15
上述代码创建一个Integer类型的列表,并将其转换成Stream对象。接下来调用reduce()方法,对每个元素执行累加操作并返回包含结果的Optional对象。最后使用ifPresent()方法打印结果,因为reduce()方法返回的是Optional对象,防止出现空指针异常。
除了以上的无起始值版本 reduce(BinaryOperator<T> accumulator) 以外,还有包含起始值的版本 reduce(T identity, BinaryOperator<T> accumulator),该方法中第一个参数identity表示初始值,可以避免空指针异常,起始时的结果即为初始值。例如,以下代码演示了如何使用带有起始值的reduce()方法计算整数列表中所有元素的和:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int result = list.stream().reduce(0, (a, b) -> a + b); System.out.println(result); // 输出15
上述代码创建一个Integer类型的列表,并将其转换成Stream对象。接下来调用reduce()方法,指定初始值为0,对每个元素执行累加操作并返回最终结果。最后打印结果,因为reduce()方法返回的是基本数据类型。
reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)方法是一个终止操作,用于将所有元素归约成单个结果。该方法接收三个参数:第一个参数为初始值identity,第二个参数为BiFunction函数,用于将每个元素转换为某个类型U,并与上一个部分结果进行累加操作,第三个参数为BinaryOperator函数,用于对合并所有部分结果进而得到最终结果。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)方法,并传入一个初始值、一个BiFunction函数和一个BinaryOperator函数。
- 该方法将在整个流上执行指定的累加操作,并返回结果。
例如,以下代码演示了如何使用reduce()方法计算字符串列表中所有元素的长度之和:
List<String> list = Arrays.asList("java", "python", "ruby"); int result = list.stream().reduce(0, (sum, str) -> sum + str.length(), Integer::sum); System.out.println(result); // 输出14
上述代码创建一个String类型的列表,并将其转换成Stream对象。接下来调用reduce()方法,指定初始值为0,将每个元素的长度累加到初始值上,并使用Integer::sum方法将所有部分结果进行合并。最后打印结果,因为reduce()方法返回的是基本数据类型,无需使用isPresent()方法判断结果是否存在。
需要注意的是,由于该方法可以进行并行操作,因此每个部分结果都需要使用BiFunction函数进行累加,最终结果还需要使用BinaryOperator函数进行合并。如果流中有多个部分结果,则会调用BinaryOperator函数将它们合并成一个结果。
collect(Collector<? super T,A,R> collector)
collect(Collector<? super T,A,R> collector)
方法是 Java 8 中Stream
接口提供的一个方法,用于将流中的元素收集到容器对象中。该方法接收一个Collector
对象作为参数,该对象定义了如何对流中的元素进行收集,并将结果放入一个容器对象中。下面是一个使用示例:
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class StreamCollectExample { public static void main(String[] args) { List<String> names = Stream.of("Tom", "Jerry", "Mickey", "Minnie") .filter(name -> name.startsWith("M")) .collect(Collectors.toList()); System.out.println(names); // [Mickey, Minnie] List<Integer> numbers = Stream.iterate(1, n -> n + 1) .limit(10) .collect(Collectors.toCollection(ArrayList::new)); System.out.println(numbers); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] int sum = Stream.of(1, 2, 3, 4, 5) .collect(Collectors.summingInt(Integer::intValue)); System.out.println(sum); // 15 String joined = Stream.of("Hello", "world") .collect(Collectors.joining(", ")); System.out.println(joined); // "Hello, world" } }
以上代码展示了四种使用
collect()
方法的示例。第一个示例中,使用Collectors.toList()
将流中以字母 "M" 开头的字符串收集到一个List
对象中。第二个示例中,使用Collectors.toCollection(ArrayList::new)
将流中前 10 个整数收集到一个ArrayList
对象中。第三个示例中,使用Collectors.summingInt(Integer::intValue)
计算流中整数的和。第四个示例中,使用Collectors.joining(", ")
将流中的字符串连接成一个字符串。在使用
collect()
方法时,需要注意Collector
对象的定义,它定义了收集流元素的方式。常用的Collector
实现类有toList()
、toSet()
、toMap()
、summingInt()
、joining()
等,可以根据具体的需求选择使用。
collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
方法是 Java 8 中Stream
接口提供的一个方法,用于将流中的元素收集到容器对象中。该方法接收三个参数:
supplier
:提供容器对象的工厂方法。accumulator
:对流中的元素进行收集的累加器函数。combiner
:将两个容器对象合并为一个的函数。下面是一个使用示例:
import java.util.ArrayList; import java.util.List; public class StreamCollectExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Tom"); list.add("Jerry"); list.add("Mickey"); list.add("Minnie"); List<String> result = list.stream().collect( ArrayList::new, (l, s) -> { if (s.startsWith("M")) { l.add(s); } }, List::addAll); System.out.println(result); // [Mickey, Minnie] } }
以上代码展示了使用
collect()
方法进行自定义收集的示例。首先创建了一个ArrayList
对象作为容器对象,并将一些字符串添加到该对象中。然后通过stream()
方法获取流,并通过collect()
方法进行自定义收集。在这个收集过程中,使用
ArrayList::new
提供一个ArrayList
的工厂方法来创建容器对象;使用(l, s) -> {...}
定义一个累加器函数,在其中仅将以字母 "M" 开头的字符串添加到容器对象中;使用List::addAll
定义一个合并容器对象的函数,将多个容器对象的元素合并为一个。最终,得到一个包含以字母 "M" 开头的字符串的列表。需要注意的是,在使用
collect()
方法时,需要根据具体的需求选择不同的收集方式,正确的实现Supplier<R>
、BiConsumer<R, ? super T>
和BiConsumer<R, R>
这三个函数接口才能够成功地收集流中的元素。
max(Comparator<? super T> comparator)
max(Comparator<? super T> comparator)方法是一个终止操作,用于返回此流中的最大元素,根据指定的Comparator比较元素。返回的类型为Optional<T>,如果流为空,则返回一个空的Optional对象。
该方法只能用于有限长度的流,因为需要在整个流上执行比较操作以找到最大元素。该方法执行的时间复杂度为O(n),其中n是流中的元素数量。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用max(Comparator<? super T> comparator)方法,并传入一个Comparator对象。
- 该方法将在整个流上执行比较操作,并找到最大元素。
- 返回类型为Optional<T>,通过.get()方法获取其中的值。
例如,以下代码演示了如何使用max()方法找到流中的最大元素:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> max = list.stream().max(Integer::compare); if(max.isPresent()) { System.out.println("The maximum element is " + max.get()); }
输出结果为:"The maximum element is 5",因为5是列表中的最大元素。注意,max()方法返回的是Optional对象,因此需要判断是否存在最大值再进行其它操作。
min(Comparator<? super T> comparator)
min(Comparator<? super T> comparator)方法是一个终止操作,用于返回此流中的最小元素,根据指定的Comparator比较元素。返回的类型为Optional<T>,如果流为空,则返回一个空的Optional对象。
该方法只能用于有限长度的流,因为需要在整个流上执行比较操作以找到最小元素。该方法执行的时间复杂度为O(n),其中n是流中的元素数量。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用min(Comparator<? super T> comparator)方法,并传入一个Comparator对象。
- 该方法将在整个流上执行比较操作,并找到最小元素。
- 返回类型为Optional<T>,通过.get()方法获取其中的值。
例如,以下代码演示了如何使用min()方法找到流中的最小元素:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> min = list.stream().min(Integer::compare); if(min.isPresent()) { System.out.println("The minimum element is " + min.get()); }
输出结果为:"The minimum element is 1",因为1是列表中的最小元素。注意,min()方法返回的是Optional对象,因此需要判断是否存在最小值再进行其它操作。
count()
count()
方法是用来计算流中元素数量的方法。下面是一个使用示例:
import java.util.Arrays; import java.util.List; public class StreamCountExample { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); long count = list.stream().count(); System.out.println("Count: " + count); // 输出 Count: 5 } }
以上代码展示了如何使用
count()
方法计算流中元素的数量。首先创建了一个整型列表list
,然后通过stream()
方法将其转换为一个流。接着,使用count()
方法获取流中元素的数量,得到一个长整型值count
,最终将其打印出来。需要注意的是,
count()
方法返回的是一个长整型值,表示流中元素的数量。如果流为空,则返回值为 0。此外,由于count()
方法返回的是一个终止操作,所以在调用该方法之后无法对同一个流再进行其他操作。
allMatch(Predicate<? super T> predicate)
allMatch(Predicate<? super T> predicate)
方法用于判断流中的所有元素是否都符合指定的条件,如果都符合则返回true
,否则返回false
。Predicate
参数是一个判断条件,接受一个 T 类型的参数,返回一个 boolean 类型的结果。以下是
allMatch()
方法的使用示例:List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); // 判断是否所有元素都大于 0 boolean allPositive = list.stream() .allMatch(x -> x > 0); System.out.println(allPositive); // true // 判断是否所有元素都小于 3 boolean allLessThanThree = list.stream() .allMatch(x -> x < 3); System.out.println(allLessThanThree); // false
上述代码中,首先创建了一个包含 1 到 5 的整数列表,然后使用
allMatch()
方法,分别判断了列表中的元素是否都大于 0 和是否都小于 3,并将结果输出到控制台。注意,当流为空时,
allMatch()
方法会返回true
。
anyMatch(Predicate<? super T> predicate)
anyMatch(Predicate<? super T> predicate)
方法用于判断流中的元素是否存在至少一个符合指定条件,如果存在则返回true
,否则返回false
。Predicate
参数是一个判断条件,接受一个 T 类型的参数,返回一个 boolean 类型的结果。以下是
anyMatch()
方法的使用示例:List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); // 判断是否存在大于 3 的元素 boolean existsGreaterThanThree = list.stream() .anyMatch(x -> x > 3); System.out.println(existsGreaterThanThree); // true // 判断是否存在小于 0 的元素 boolean existsLessThanZero = list.stream() .anyMatch(x -> x < 0); System.out.println(existsLessThanZero); // false
上述代码中,首先创建了一个包含 1 到 5 的整数列表,然后使用
anyMatch()
方法,分别判断了列表中的元素是否存在大于 3 的元素和是否存在小于 0 的元素,并将结果输出到控制台。注意,当流为空时,
anyMatch()
方法会返回false
。
noneMatch(Predicate<? super T> predicate)
noneMatch(Predicate<? super T> predicate)方法是一个终止操作,用于检查流中的所有元素是否都不满足指定的Predicate条件。如果所有元素都不满足条件,则返回true;否则返回false。
该方法执行的时间复杂度为O(n),其中n是流中的元素数量。
具体用法如下:
- 创建一个包含多个元素的Stream对象。
- 调用noneMatch(Predicate<? super T> predicate)方法,并传入一个Predicate对象。
- 该方法将在整个流上执行检查操作,并返回一个布尔值表示是否所有元素都不满足条件。
例如,以下代码演示了如何使用noneMatch()方法检查流中的所有元素是否为偶数:
List<Integer> list = Arrays.asList(1, 3, 5, 7); boolean result = list.stream().noneMatch(x -> x % 2 == 0); if(result) { System.out.println("All the elements are odd numbers."); } else { System.out.println("There are even numbers in the list."); }
输出结果为:"All the elements are odd numbers.",因为在给定的列表中没有偶数。如果列表中存在偶数,则输出结果为"There are even numbers in the list."。
findAny()
findAny()
方法是用来返回当前流中的任意一个元素。它可以和filter()
方法一起使用,以便在找到符合条件的元素时能够立即返回。下面是一个使用示例:
import java.util.Arrays; import java.util.List; public class StreamFindAnyExample { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Integer result = list.stream() .filter(n -> n % 2 == 0) .findAny() .orElse(null); System.out.println(result); // 输出 2 或 4 } }
以上代码展示了如何使用
findAny()
方法返回当前流中的任意一个元素。首先创建了一个整型列表list
,然后通过stream()
方法将其转换为一个流。接着,使用filter(n -> n % 2 == 0)
方法得到一个新的流,其中仅包含偶数元素,并使用findAny()
方法返回其中的任意一个元素。由于该流中有多个偶数元素,因此返回值可能为 2 或 4。最终通过orElse(null)
方法处理返回值,并将其打印出来。需要注意的是,如果流中没有任何元素,则
findAny()
方法将会返回一个空的Optional
对象。因此,在上述代码中,通过orElse(null)
方法处理了可能为空的返回值。
findFirst()
findFirst()
方法是用来返回当前流中的第一个元素。它可以和 filter()
方法一起使用,以便在找到符合条件的元素时能够立即返回。
下面是一个使用示例:
import java.util.Arrays;
import java.util.List;
public class StreamFindFirstExample {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer result = list.stream()
.filter(n -> n % 2 == 0)
.findFirst()
.orElse(null);
System.out.println(result); // 输出 2
}
}
以上代码展示了如何使用 findFirst()
方法返回当前流中的第一个元素。首先创建了一个整型列表 list
,然后通过 stream()
方法将其转换为一个流。接着,使用 filter(n -> n % 2 == 0)
方法得到一个新的流,其中仅包含偶数元素,并使用 findFirst()
方法返回其中的第一个元素。由于该流中有多个偶数元素,因此返回值为 2。最终通过 orElse(null)
方法处理返回值,并将其打印出来。
需要注意的是,如果流中没有任何元素,则 findFirst()
方法将会返回一个空的 Optional
对象。因此,在上述代码中,通过 orElse(null)
方法处理了可能为空的返回值。另外,如果流中的元素是无序的,则返回的将是其中的任何一个元素。