Java8 教程

Java8 简单的聚合方法

你已经了解了如何创建和转换流,接下来将介绍最重要的一点 —— 如何从流数据中找到答案。我们在本节中介绍的方法统称为聚合方法。它们会将流聚合为一个值,以便在程序中使用。聚合方法都是终止操作。当一个流应用了终止操作后,它就不能再应用其他的操作了。

count 方法

在 Java8 的 Stream API 中,count 方法是一个终端操作(terminal operation),用于计算流中元素的数量。它返回流中元素的个数,这个计数是一个 long 类型的值。

方法定义:

long count()

示例:

统计 list 中元素的个数,如下:

package com.hxstrive.jdk8.stream_api;

import java.util.ArrayList;
import java.util.List;

/**
 * count 方法
 * @author hxstrive.com
 */
public class StreamCountDemo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add("three");

        // 跳过流前 2 个元素,并输出这些元素
        long count = list.stream().count();
        System.out.println("count = " + count);
        //输出:
        //count = 3
    }

}

注意:count 是一个终端操作,这意味着一旦你调用了它,流就会被消费掉,并且你不能再次在这个流上执行其他操作。如果你需要再次使用流中的数据,你需要重新创建流。

max 和 min 方法

Java8 聚合方法是 max 和 min,分别返回流中最大值和最小值。需要注意的一点是 —— 这些方法会返回一个 Optional<T> 值,它可能会封装返回值,也可能表示没有返回 (当流为空时)。在我们之前使用 Java 的时候,这种情况通常会返回 null,但是如果在一个未经完全测试的程序中产生了异常情况,那样会导致抛出空指针异常。在 Java8 中,Optional 类型是一种更好的表示缺少返回值的方式。

方法定义:

// 根据提供的 Comparator返回此流的最大元素
Optional<T> max(Comparator<? super T> comparator)
// 根据提供的 Comparator返回此流的最小元素
Optional<T> min(Comparator<? super T> comparator)

示例:

下面示例将获取流中最大值和最小值的值,如下:

package com.hxstrive.jdk8.stream_api;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * max 和 min 方法
 * @author hxstrive.com
 */
public class StreamMaxDemo {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

        // 最小值 min
        Optional<Integer> min = list.stream().min(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        min.ifPresent(System.out::println); // 输出:1

        list.stream().min((o1,o2) -> o1.compareTo(o2)).ifPresent(System.out::println); // 输出:1
        list.stream().min(Comparator.naturalOrder()).ifPresent(System.out::println); // 输出:1
        list.stream().min(Integer::compareTo).ifPresent(System.out::println); // 输出:1

        // 最大值 max
        Optional<Integer> max = list.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        max.ifPresent(System.out::println); // 输出:5

        list.stream().max((o1,o2) -> o1.compareTo(o2)).ifPresent(System.out::println); // 输出:5
        list.stream().max(Comparator.naturalOrder()).ifPresent(System.out::println); // 输出:5
        list.stream().max(Integer::compareTo).ifPresent(System.out::println); // 输出:5
    }

}

findFirst 方法

findFirst 方法会返回非空集合中的第一个值,它通常与 filter 方法结合起来使用。例如,我们可以找到以字母 t 开头的第一个单词 (如果它存在的话):

package com.hxstrive.jdk8.stream_api;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * findFirst 方法
 * @author hxstrive.com
 */
public class StreamFindFirstDemo {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("one", "two","three", "four", "five");

        // 获取第一个以 "t" 开头的元素
        Optional<String> start = list.stream().filter(e -> {
            System.out.println("filter -> " + e);
            return e.startsWith("t");
        }).findFirst();
        start.ifPresent(System.out::println);
        //输出:
        //filter -> one
        //filter -> two
        //two
    }

}

从上例输出可知,当找到第一个以“t”开头的元素后,filter 将会停止继续处理后续元素,即 filter 是可以中断的。

findAny 方法

如果你想找到所有匹配的元素 (而不只是第一个),那么可以使用 findAny 方法。这个方法在对流进行并行执行时十分有效,因为只要在任何片段中发现了第一个匹配元素,都会结束整个计算。例如:

package com.hxstrive.jdk8.stream_api;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * findAny 方法
 * @author hxstrive.com
 */
public class StreamFindAnyDemo {

    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

        // 串行流示例
        Optional<String> anyNameSerial = names.stream().findAny();
        anyNameSerial.ifPresent(System.out::println); // 可能输出 Alice、Bob、Charlie 或 David 中的任意一个

        // 并行流示例
        Optional<String> anyNameParallel = names.parallelStream().findAny();
        anyNameParallel.ifPresent(System.out::println); // 在并行流中,输出可能是随机的
    }

}

anyMatch 方法

如果你只希望知道流中是否含有匹配元素,可以使用 anyMatch 方法。该方法可以接受一个 Predicate 参数,因此你不需要使用 filter 方法。例如:

package com.hxstrive.jdk8.stream_api;

import java.util.Arrays;
import java.util.List;

/**
 * anyMatch 方法
 * @author hxstrive.com
 */
public class StreamAnyMatchDemo {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("one", "two","three", "four", "five");

        // 同步执行
        // 判断流中是否存在 “two” 字符串,true 表示存在,false 表示不存在
        boolean flag = list.stream().anyMatch(s -> "two".endsWith(s));
        System.out.println(flag); // true

        // 并行执行
        boolean flag2 = list.parallelStream().anyMatch(s -> "two".equals(s));
        System.out.println(flag2); // true
    }

}

Java8 中还提供了两个方法 allMatch noneMatch,它们分别在所有元素均匹配和没有元素匹配 Predicate 时返回 true。虽然这些方法总是会检查整个流,但是仍可以通过并行执行来提高速度。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号