当前位置: 首页 > news >正文

Java8 Stream流:过滤、归约与并行计算

什么是Stream流

        Stream流是 Java8 引入的一个的新的API,用于以声明式编程风格高效处理集合、数组或I/O资源等数据。通过链式操作的方式对数据进行计算,最终产生结果。

为什么要引入Stream流API

        我们在使用Stream流之前操作集合的时候,可能会存在部分逻辑导致多层循环嵌套,这样会导致代码的可读性变差、代码冗余度变高。同时,如果逻辑中存在需要进行并行计算的地方,并行的复杂度比较大,手动去管理多线程可能会出现问题。

        因此,Java8引入了Stream流这个API,用于简化传统的集合操作,通过声明式编程范式和函数式编程思想快速进行数据集合的处理。

题外话:声明式编程和命令式编程

  • 命令式编程的核心思想在于开发者通过编写具体的步骤指令告诉计算机该如何做。

  • 声明式编程的核心思想在于开发者通过描述做什么,而非具体步骤,让底层框架自动处理如何做。

        命令式编程关注于控制流程、强调状态的变化,而声明式编程的重点关注于结果目标而不在乎中间细节,强调没有副作用。Stream流就是声明式编程的典型示例,抽象层级高,通过组合操作处理数据流,代码简洁,可维护性强。


如何创建Stream流

一、从集合创建

        通过 Collection.steram() 或 Collection.parallelStream() 创建顺序流或者并行流。

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();       // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流

二、从数组创建

        通过 Arrays.stream(T[] arr) 创建数组的stream流。

String[] array = {"Java", "Stream", "API"};
Stream<String> stream = Arrays.stream(array);

// 处理原始类型数组(避免装箱)
int[] intArray = {1, 2, 3};
IntStream intStream = Arrays.stream(intArray);

三、直接用数据创建

        通过 Stream.of(T... values)。

Stream<String> stream = Stream.of("A", "B", "C");
Stream<Integer> numberStream = Stream.of(1, 2, 3);

四、生成连续数据序列流

// 生成1~5(不包含5)的整数流
IntStream.range(1, 5).forEach(System.out::print);  // 输出:1234

// 生成1~5(包含5)的整数流
IntStream.rangeClosed(1, 5).forEach(System.out::print); // 输出:12345

Stream流的核心操作

        Stream流的核心操作分为中间操作和终端操作,下面进行分别介绍。

一、中间操作

过滤(Filter)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evens = numbers.stream()
                            .filter(n -> n % 2 == 0)  // 过滤偶数
                            .collect(Collectors.toList());  // [2,4]

映射(Map)

List<String> words = Arrays.asList("apple", "banana");
List<Integer> lengths = words.stream()
                            .map(String::length)  // 映射为单词长度
                            .collect(Collectors.toList());  // [5, 6]

扁平化映射(FlatMap)

List<List<String>> nestedList = Arrays.asList(
    Arrays.asList("a", "b"), 
    Arrays.asList("c", "d")
);
List<String> flatList = nestedList.stream()
                                .flatMap(Collection::stream)  // 展开为 "a","b","c","d"
                                .collect(Collectors.toList());

去重(Distinct)

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3);
List<Integer> unique = numbers.stream()
                             .distinct()
                             .collect(Collectors.toList());  // [1,2,3]

排序(Sorted)

List<String> names = Arrays.asList("Bob", "Alice", "Charlie");
List<String> sorted = names.stream()
                          .sorted()  // 自然排序:["Alice", "Bob", "Charlie"]
                          .collect(Collectors.toList());

分页(Limit)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> subList = numbers.stream()
                              .skip(2)  // 跳过前2个元素:[3,4,5]
                              .limit(2) // 取前2个元素:[3,4]
                              .collect(Collectors.toList());

二、终端操作

遍历(ForEach)

List<String> names = Arrays.asList("Alice", "Bob");
names.stream().forEach(System.out::println);  // 输出每个名字

收集(Collect)

// 转为List/Set
List<Integer> list = stream.collect(Collectors.toList());
Set<Integer> set = stream.collect(Collectors.toSet());

// 转为Map
Map<Integer, String> map = users.stream()
    .collect(Collectors.toMap(User::getId, User::getName));

// 分组统计
Map<String, List<User>> groupByCity = users.stream()
    .collect(Collectors.groupingBy(User::getCity));

// 拼接字符串
String joined = stream.collect(Collectors.joining(", "));

归约(Reduce)

int sum = numbers.stream()
                .reduce(0, Integer::sum);  // 初始值0,累加所有元素

Optional<Integer> max = numbers.stream()
                              .reduce(Integer::max);  // 无初始值,返回Optional

匹配(Match)

boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);  // 是否存在偶数
boolean allPositive = numbers.stream().allMatch(n -> n > 0);   // 是否全为正数

查找(Find)

Optional<Integer> first = numbers.stream().findFirst();
Optional<Integer> any = numbers.parallelStream().findAny();  // 并行时可能随机返回

统计(Count/Min/Max)

long count = numbers.stream().count();
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
Optional<Integer> max = numbers.stream().max(Integer::compareTo);

Stream流高级特性

并行

        Stream的并行流底层基于Fork/Join框架,自动拆分任务到线程池中,可以进行并行计算。下面列出一个表格用于标识顺序流和并行流在一些场景下的性能对比,表格来源网络。

场景

数据量

顺序流耗时

并行流耗时

加速比

简单过滤+统计

10万

12 ms

8 ms

1.5x

复杂计算(如加密)

10万

350 ms

85 ms

4.1x

排序操作

10万

45 ms

60 ms

0.75x

        我们应该根据情况合理选用不同的流:当数据量小且操作简单的时候,我们应该优先选择顺序流;当数据量较大且操作复杂的时候,我们应该选用并行流。


总结

        Java为我们提供了一种新的操作集合的方法,通过Stream流可以简化我们的编码,让我们代码的可读性和可维护性得到提升;同时,对于一些特殊情况下,Stream流也可以加快我们的计算速度。根据实际场景,选用适合的操作。

http://www.dtcms.com/a/111565.html

相关文章:

  • VirtualBox中安装Win10教程
  • Joomla教程—常用模块 - 登录模块与常用模块 - 文章列表
  • RISC-V debug专栏1 --- Introduction
  • 杰文字悖论:效率提升的副作用
  • 文档处理利器Docling,基于LangChain打造RAG应用
  • 【Cursor/VsCode】在文件列表中不显示.meta文件
  • Vue 项目使用 pdf.js 及 Elasticpdf 教程
  • pyTorch框架:模型的子类写法--改进版二分类问题
  • 【Ragflow】11. 文件解析流程分析/批量解析实现
  • 计算机视觉算法实战——基于YOLOv8的自动驾驶障碍物实时感知系统
  • linux gcc
  • 【读书笔记·VLSI电路设计方法解密】问题62:什么是故障覆盖率,什么是百万缺陷率
  • 【算法/c++】利用中序遍历和后序遍历建二叉树
  • Axure RP 9 详细图文安装流程(附安装包)教程包含下载、安装、汉化、授权
  • 3维格式转换(二)
  • AI医疗诊疗系统设计方案
  • Qt QComboBox 下拉复选多选
  • 常用的国内镜像源
  • MSF上线到CS工具中 实战方案(可执行方案)
  • ZLMediaKit 源码分析——[5] ZLToolKit 中EventPoller之延时任务处理
  • [特殊字符] 驱动开发硬核特训 · Day 2
  • Python爬取新浪微博内容实战:从API解析到数据存储
  • [Linux系统编程]进程信号
  • 基于Java的区域化智慧养老系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 146. LRU 缓存 带TTL的LRU缓存实现(拓展)
  • Spring项目中使用@Data或@Slf4j等注解,发生找不到符号异常错误解决办法
  • 【Python】Python环境管理工具UV安装gdal
  • Docker 命令简写配置
  • 【进收藏夹吃灰】机器学习学习指南
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——