目 录CONTENT

文章目录

Stream

半糖
2024-08-07 / 0 评论 / 0 点赞 / 27 阅读 / 15405 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-08-07,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

概念

Stream 是一种用于处理集合数据的流抽象。

它提供了一种对集合元素进行各种操作的简洁而强大的方式,这些操作可以是过滤、映射、排序、聚合等。通过 Stream 可以以

函数式编程的风格对数据进行高效的处理和转换,避免了繁琐的传统循环操作。

Stream类型对象的获取方式

Collection的获取

stream():调用此方法返回Stream类型的对象

示例

    @Test
    public void test1() {
        Predicate<Integer> predicate = (m) -> m % 2 == 0;
        List<Integer> list = ListUtil.toList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 不使用Stream的写法
        for (Integer i : list) {
            if (predicate.test(i)) {
                System.out.println(i);
            }
        }

        // 使用Stream的写法
        list.stream().filter(predicate).forEach(System.out::println);
    }

Map的获取

不能直接获取到Stream类型,根据情况选择合适的方法

  • keySet().stream():先获取键的集合,再获取键集合的stream类型对象

  • values().stream():先获取值得集合,再获取值集合的Stream类型对象

  • entrySet().stream():先获取键值对集合,再获取键值对集合的Stream对象

示例

    @Test
    public void test2() {
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("张三", 1);
        map.put("李四", 2);
        map.put("王麻子", 3);

        Predicate<String> predicate = (m) -> m.startsWith("张");
        
        // keySet().stream()
        map.keySet().stream().filter(predicate).forEach(m -> System.out.println(m + " " + map.get(m)));
        
        // values().stream()
        map.values().stream().forEach(System.out::println);
        
        // entrySet().stream()
        map.entrySet().stream().filter(m -> predicate.test(m.getKey())).forEach(m -> System.out.println(m.getKey() + " " + m.getValue()));
    }

数组的获取

Stream.of( 数组 ):将数组转化成stream类型

示例

    @Test
    public void test3() {
        Stream.of(new int[]{1, 2, 3, 4, 5}).forEach(System.out::println);
    }

流式API

Java 8新增了Stream、IntStream、LongStream、DoubleStream等流式API,这些API代表多个支持串行和并行聚集操作的元素。

Stream是一个通用的流接口,而IntStream、LongStream、DoubleStream则代表元素类型为int、long、double的流。

用法

为每个流式API提供了对应的Builder(Stream.Builder、IntStream.Builder、LongStream.Builder、DoubleStream.Builder),可以通过这些Builder来创建对应的流。

  1. 使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder。

  2. 重复调用Builder的add()方法向该流中添加多个元素。

  3. 调用Builder的build()方法获取对应的Stream。

  4. 调用Stream的聚集方法(stream的那些方法)

示例

    @Test
    public void test4() {
        Predicate<Integer> predicate = (m) -> m % 2 == 0;

        Stream.Builder<Integer> builder = Stream.builder();
        builder.add(1).add(2).add(3).add(4).add(5).add(6).add(7).add(8).add(9).add(10)
                .build()
                .filter(predicate)
                .forEach(System.out::println);

        IntStream.Builder intBuilder = IntStream.builder();
        intBuilder.add(1).add(2).add(3).add(4).add(5).add(6).add(7).add(8).add(9).add(10)
                .build()
                .filter(predicate::test)
                .forEach(System.out::println);
    }

Stream的方法

中间方法

中间操作允许流保持打开状态,并允许直接调用后续方法,中间方法的返回值是另外一个流

  • filter(Predicate predicate):筛选出Stream中所有符合predicate的元素。

  • mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素。

  • peek(Consumer action):依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的元素。该方法主要用于调试。

  • distinct():该方法用于去除流中所有重复的元素(判断元素重复的标准是使用equals()比较返回true)。这是一个有状态的方法

  • sorted():该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法

  • limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态的、短路方法

末端方法

末端方法是对流的最终操作。当对某个Stream执行末端方法后,该流将会被“消耗”且不再可用。

  • forEach(Consumer action):遍历流中所有元素,对每个元素执行action。

  • toArray():将流中所有元素转换为一个数组。

  • reduce():该方法有三个重载的版本,都用于通过某种操作来合并流中的元素。

  • min():返回流中所有元素的最小值。

  • max():返回流中所有元素的最大值。

  • count():返回流中所有元素的数量。

  • anyMatch(Predicate predicate):判断流中是否至少包含一个元素符合Predicate条件。

  • noneMatch(Predicate predicate):判断流中是否所有元素都不符合Predicate条件。

  • findFirst():返回流中的第一个元素。

  • findAny():返回流中的任意一个元素。

有特征的方法

  • 有状态的方法:这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等。有状态的方法往往需要更大的性能开销。

  • 短路方法:短路方法可以尽早结束对流的操作,不必检查所有的元素。

示例(所有方法)

    @Test
    public void test5() {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // filter(Predicate predicate): 筛选出所有偶数
        List<Integer> evenNumbers = numbers.stream()
            .filter(n -> n % 2 == 0)
            .collect(Collectors.toList());
        System.out.println("偶数: " + evenNumbers);

        // map(Function mapper): 将每个数字映射为其平方
        List<Integer> squaredNumbers = numbers.stream()
            .map(n -> n * n)
            .collect(Collectors.toList());
        System.out.println("平方后的数字: " + squaredNumbers);

        // mapToInt(ToIntFunction mapper): 将每个数字映射为其平方并返回 IntStream
        IntStream squaredIntNumbers = numbers.stream()
            .mapToInt(n -> n * n);
        System.out.println("平方后的整数流: " + squaredIntNumbers.boxed().collect(Collectors.toList()));

        // mapToLong(ToLongFunction mapper): 将每个数字映射为其平方并返回 LongStream
        LongStream squaredLongNumbers = numbers.stream()
            .mapToLong(n -> n * n);
        System.out.println("平方后的长整数流: " + squaredLongNumbers.boxed().collect(Collectors.toList()));

        // mapToDouble(ToDoubleFunction mapper): 将每个数字映射为其平方并返回 DoubleStream
        DoubleStream squaredDoubleNumbers = numbers.stream()
            .mapToDouble(n -> n * n);
        System.out.println("平方后的双精度流: " + squaredDoubleNumbers.boxed().collect(Collectors.toList()));

        // flatMap(Function mapper): 将流中的每个元素映射为另一个流,然后将这些流合并成一个流
        List<Integer> flattenedNumbers = numbers.stream()
            .flatMap(n -> IntStream.rangeClosed(1, n).boxed())
            .collect(Collectors.toList());
        System.out.println("扁平化后的数字: " + flattenedNumbers);

        // flatMapToInt(Function mapper): 将流中的每个元素映射为另一个 IntStream,然后将这些流合并成一个 IntStream
        IntStream flattenedIntNumbers = numbers.stream()
            .flatMapToInt(n -> IntStream.rangeClosed(1, n));
        System.out.println("扁平化后的整数流: " + flattenedIntNumbers.boxed().collect(Collectors.toList()));

        // flatMapToLong(Function mapper): 将流中的每个元素映射为另一个 LongStream,然后将这些流合并成一个 LongStream
        LongStream flattenedLongNumbers = numbers.stream()
            .flatMapToLong(n -> LongStream.rangeClosed(1L, n));
        System.out.println("扁平化后的长整数流: " + flattenedLongNumbers.boxed().collect(Collectors.toList()));

        // flatMapToDouble(Function mapper): 将流中的每个元素映射为另一个 DoubleStream,然后将这些流合并成一个 DoubleStream
        DoubleStream flattenedDoubleNumbers = numbers.stream()
            .flatMapToDouble(n -> DoubleStream.of(n));
        System.out.println("扁平化后的双精度流: " + flattenedDoubleNumbers.boxed().collect(Collectors.toList()));

        // distinct(): 去除重复元素
        List<Integer> uniqueNumbers = numbers.stream()
            .distinct()
            .collect(Collectors.toList());
        System.out.println("去重后的数字: " + uniqueNumbers);

        // sorted(): 对数字进行排序
        List<Integer> sortedNumbers = numbers.stream()
            .sorted()
            .collect(Collectors.toList());
        System.out.println("排序后的数字: " + sortedNumbers);

        // sorted(Comparator comparator): 按降序对数字进行排序
        List<Integer> sortedDescendingNumbers = numbers.stream()
            .sorted((n1, n2) -> n2 - n1)
            .collect(Collectors.toList());
        System.out.println("降序排序后的数字: " + sortedDescendingNumbers);

        // peek(Consumer action): 打印每个数字
        List<Integer> squaredAndLoggedNumbers = numbers.stream()
            .peek(System.out::println)
            .map(n -> n * n)
            .collect(Collectors.toList());
        System.out.println("打印并平方后的数字: " + squaredAndLoggedNumbers);

        // limit(long maxSize): 限制流的大小为前三个数字
        List<Integer> limitedNumbers = numbers.stream()
            .limit(3)
            .collect(Collectors.toList());
        System.out.println("限制后的数字: " + limitedNumbers);

        // skip(long n): 跳过前三个数字
        List<Integer> skippedNumbers = numbers.stream()
            .skip(3)
            .collect(Collectors.toList());
        System.out.println("跳过后的数字: " + skippedNumbers);

        // forEach(Consumer action): 遍历每个数字
        numbers.stream()
            .forEach(System.out::println);

        // forEachOrdered(Consumer action): 以有序方式遍历每个数字
        numbers.stream()
            .forEachOrdered(System.out::println);

        // toArray(): 将流转换为数组
        Integer[] numberArray = numbers.stream()
            .toArray(Integer[]::new);
        System.out.println("数组: " + Arrays.toString(numberArray));

        // reduce(BinaryOperator accumulator): 计算所有数字的总和
        int sum = numbers.stream()
            .reduce(0, Integer::sum);
        System.out.println("总和: " + sum);

        // reduce(T identity, BinaryOperator accumulator): 计算所有数字的乘积
        int product = numbers.stream()
            .reduce(1, (a, b) -> a * b);
        System.out.println("乘积: " + product);

        // reduce(Predicate predicate, BinaryOperator combiner): 检查是否至少有一个偶数
        boolean containsEven = numbers.stream()
            .reduce(false, (acc, n) -> acc || n % 2 == 0, (acc1, acc2) -> acc1 || acc2);
        System.out.println("是否包含偶数: " + containsEven);

        // collect(Collector collector): 收集数字到列表
        List<Integer> collectedNumbers = numbers.stream()
            .collect(Collectors.toList());
        System.out.println("收集后的数字: " + collectedNumbers);

        // min(Comparator comparator): 查找最小值
        Integer min = numbers.stream()
            .min(Integer::compare)
            .orElse(null);
        System.out.println("最小值: " + min);

        // max(Comparator comparator): 查找最大值
        Integer max = numbers.stream()
            .max(Integer::compare)
            .orElse(null);
        System.out.println("最大值: " + max);

        // count(): 计算元素数量
        long count = numbers.stream()
            .count();
        System.out.println("计数: " + count);

        // anyMatch(Predicate predicate): 检查是否存在至少一个偶数
        boolean hasEven = numbers.stream()
            .anyMatch(n -> n % 2 == 0);
        System.out.println("是否存在偶数: " + hasEven);

        // allMatch(Predicate predicate): 检查所有数字是否都是偶数
        boolean allEven = numbers.stream()
            .allMatch(n -> n % 2 == 0);
        System.out.println("所有数字是否都是偶数: " + allEven);

        // noneMatch(Predicate predicate): 检查是否存在任何偶数
        boolean noEven = numbers.stream()
            .noneMatch(n -> n % 2 == 0);
        System.out.println("不存在偶数: " + noEven);

        // findFirst(): 查找第一个元素
        Integer first = numbers.stream()
            .findFirst()
            .orElse(null);
        System.out.println("第一个元素: " + first);

        // findAny(): 查找任意元素(在并行流中可能不是第一个)
        Integer any = numbers.parallelStream()
            .findAny()
            .orElse(null);
        System.out.println("任意元素: " + any);

        // builder(): 创建 Stream.Builder
        Stream.Builder<Integer> builder = Stream.builder();
        builder.add(1).add(2).add(3);
        Stream<Integer> builtStream = builder.build();
        System.out.println("构建的流: " + builtStream.collect(Collectors.toList()));

        // empty(): 创建空的 Stream
        Stream<Integer> emptyStream = Stream.empty();
        System.out.println("空流: " + emptyStream.collect(Collectors.toList()));

        // of(T... values): 创建包含给定值的 Stream
        Stream<Integer> ofStream = Stream.of(1, 2, 3);
        System.out.println("of 方法创建的流: " + ofStream.collect(Collectors.toList()));

        // iterate(T seed, UnaryOperator f): 根据给定的种子和迭代函数创建无限流
        Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);
        System.out.println("iterate 方法创建的流: " + iterateStream.collect(Collectors.toList()));

        // generate(Supplier s): 生成无限流,每次调用 supplier 产生一个新值
        // 这里我们生成一个无限流,每次产生一个随机数
        // 使用 limit 方法来限制流的大小
        DoubleStream randomNumbers = Stream.generate(Math::random)
                .limit(5)
                .mapToDouble(Double::doubleValue);
        System.out.println("随机数流: " + randomNumbers.boxed().collect(Collectors.toList()));

        // concat(Stream<T> a, Stream<T> b): 合并两个流
        // 创建两个 String 流
        Stream<String> stream1 = Stream.of("Hello", "World");
        Stream<String> stream2 = Stream.of("Java", "Stream");

        // 使用 concat 方法合并两个流
        Stream<String> concatenatedStream = Stream.concat(stream1, stream2);
        System.out.println("合并后的流: " + concatenatedStream.collect(Collectors.toList()));

    }


0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区