Java8 Stream详解及结束操作方法使用示例(三)

         结束操作是指结束 Stream 该如何处理的操作,并且会触发 Stream 的执行。下面是一些常用的结束操作方法。结束操作会对数据源进行遍历,因此是及早求值的。

Java8 Stream详解及中间操作方法使用示例(一)
​​​​​​​
Java8 Stream详解及创建流方法使用示例(二)
 

  1. forEach(Consumer<T> action):对流中的每个元素执行指定的操作。
  2. toArray():将流中的元素转换成数组。
  3. reduce(T identity, BinaryOperator<T> accumulator):使用指定的累加器对流中的元素进行聚合。
  4. collect(Collector<T,A,R> collector):将流中的元素收集到一个容器中。
  5. min(Comparator<T> comparator):返回流中的最小元素。
  6. max(Comparator<T> comparator):返回流中的最大元素。
  7. count():返回流中元素的数量。
  8. anyMatch(Predicate<T> predicate):判断流中是否有任意一个元素匹配指定的条件。
  9. allMatch(Predicate<T> predicate):判断流中是否所有元素都匹配指定的条件。
  10. noneMatch(Predicate<T> predicate):判断流中是否没有任何一个元素匹配指定的条件。
  11. findFirst():返回流中的第一个元素。
  12. 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类型的数组,可以使用泛型类型推断进行强制类型转换。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用toArray()方法。
  3. 该方法将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对象中的所有元素。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用toArray(IntFunction<A[]> generator)方法,并传入一个IntFunction函数。
  3. 该方法将使用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函数作为参数,用于对流中的元素执行累加操作。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用reduce(BinaryOperator<T> accumulator)方法,并传入一个BinaryOperator函数。
  3. 该方法将在整个流上执行指定的累加操作,并返回包含结果的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函数,用于对合并所有部分结果进而得到最终结果。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)方法,并传入一个初始值、一个BiFunction函数和一个BinaryOperator函数。
  3. 该方法将在整个流上执行指定的累加操作,并返回结果。

例如,以下代码演示了如何使用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是流中的元素数量。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用max(Comparator<? super T> comparator)方法,并传入一个Comparator对象。
  3. 该方法将在整个流上执行比较操作,并找到最大元素。
  4. 返回类型为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是流中的元素数量。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用min(Comparator<? super T> comparator)方法,并传入一个Comparator对象。
  3. 该方法将在整个流上执行比较操作,并找到最小元素。
  4. 返回类型为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,否则返回 falsePredicate 参数是一个判断条件,接受一个 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,否则返回 falsePredicate 参数是一个判断条件,接受一个 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是流中的元素数量。

具体用法如下:

  1. 创建一个包含多个元素的Stream对象。
  2. 调用noneMatch(Predicate<? super T> predicate)方法,并传入一个Predicate对象。
  3. 该方法将在整个流上执行检查操作,并返回一个布尔值表示是否所有元素都不满足条件。

例如,以下代码演示了如何使用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) 方法处理了可能为空的返回值。另外,如果流中的元素是无序的,则返回的将是其中的任何一个元素。

猜你喜欢

转载自blog.csdn.net/Ascend1977/article/details/131095060