Java Stream 流:优雅操作集合与数组的新方式

在 Java 8 中引入的 Stream API,彻底改变了我们处理集合和数组的方式。它结合 Lambda 表达式,提供了一种声明式、链式的操作风格,让数据处理代码更简洁、更易读。本文将从 Stream 的基本概念、获取方式、核心操作到实际应用,全面梳理 Stream 流的使用方法。

一、什么是 Stream 流?

Stream 流是 Java 8 新增的用于处理集合和数组的 API,它具有以下特点:

  • 流式处理:数据像水流一样在管道中传递,经过一系列操作后输出结果
  • 声明式编程:关注 "做什么" 而不是 "怎么做"
  • 链式操作:支持多个操作串联执行
  • 惰性执行:中间操作不会立即执行,直到遇到终结操作才会触发实际计算

使用 Stream 流的基本步骤:

  1. 获得一个 Stream 流(将数据放入流水线)
  2. 使用中间方法处理数据(对流水线上的数据进行加工)
  3. 使用终结方法获取结果(从流水线上取出最终数据)

二、如何获取 Stream 流?

根据数据源的不同,Stream 流有多种获取方式:

1. 从单列集合获取

所有实现了 Collection 接口的单列集合(如 List、Set)都可以通过stream()方法直接获取 Stream 流:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c", "d");
// 获取Stream流并遍历
list.stream().forEach(s -> System.out.println(s));

2. 从双列集合获取

Map 是双列集合,不能直接获取 Stream 流,需要先转换为单列集合视图:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("aaa", 111);
hashMap.put("bbb", 222);

// 方式1:获取key的Stream流
hashMap.keySet().stream().forEach(s -> System.out.println(s));

// 方式2:获取entry的Stream流
hashMap.entrySet().stream().forEach(s -> System.out.println(s));

3. 从数组获取

可以通过Arrays.stream()方法从数组获取 Stream 流:

int[] arr = {1, 2, 3, 5, 6, 7};
// 获取数组的Stream流并遍历
Arrays.stream(arr).forEach(s -> System.out.println(s));

4. 从零散数据获取

通过Stream.of()方法可以将零散数据转换为 Stream 流:

// 处理零散数据
Stream.of(1, 2, 3, 4, 5).forEach(s -> System.out.println(s));

// 注意:处理基本类型数组时会将整个数组作为一个元素
int[] nums = {1,2,3};
Stream.of(nums).forEach(System.out::println); // 输出数组地址

三、Stream 流的中间操作

中间操作会返回一个新的 Stream 流,支持链式调用,常用的中间操作包括:

1. 过滤(filter)

根据条件筛选流中的元素,符合条件的元素保留:

List<String> names = new ArrayList<>();
Collections.addAll(names, "韩孟超", "韩小孩", "王不懂", "网易");

// 筛选出以"韩"开头的名字
names.stream()
     .filter(s -> s.startsWith("韩"))
     .forEach(s -> System.out.println(s)); // 输出:韩孟超、韩小孩

2. 限制与跳过(limit/skip)

  • limit(n):保留流中的前 n 个元素
  • skip(n):跳过流中的前 n 个元素
    // 获取前3个元素
    names.stream().limit(3).forEach(System.out::println);
    
    // 跳过前3个元素,获取剩余元素
    names.stream().skip(3).forEach(System.out::println);

3. 去重(distinct)

去除流中的重复元素,依赖元素的hashCode()equals()方法:

List<String> namesWithDuplicate = new ArrayList<>();
Collections.addAll(namesWithDuplicate, "韩孟超", "韩小孩", "韩小孩");

// 去除重复元素
namesWithDuplicate.stream()
                  .distinct()
                  .forEach(System.out::println); // 输出:韩孟超、韩小孩

4. 合并流(concat)

将两个流合并为一个流:

Stream<String> stream1 = names.stream().distinct();
Stream<String> stream2 = names.stream().limit(2);

// 合并两个流
Stream.concat(stream1, stream2).forEach(System.out::println);

5. 转换类型(map)

将流中的元素转换为另一种类型:

List<String> list = new ArrayList<>();
Collections.addAll(list, "韩孟超", "王不懂");

// 将字符串转换为布尔值(是否以"韩"开头)
list.stream()
    .map(s -> s.startsWith("韩"))
    .forEach(v -> System.out.println(v)); // 输出:true、false

四、Stream 流的终结操作

终结操作会触发流的实际处理,并产生一个结果或副作用,常用的终结操作包括:

1. 遍历(forEach)

对流中的每个元素执行指定操作:

names.stream().forEach(s -> System.out.println(s));

2. 统计元素数量(count)

返回流中元素的个数:

long count = names.stream().count();
System.out.println("元素数量:" + count);

3. 收集到数组(toArray)

将流中的元素收集到数组中:

String[] array = names.stream()
                      .toArray(value -> new String[value]);
System.out.println(Arrays.toString(array));

4. 收集到集合(collect)

使用Collectors工具类将流中的元素收集到 List、Set、Map 等集合中:

// 收集到List
List<String> listResult = names.stream()
                              .filter(s -> s.startsWith("韩"))
                              .collect(Collectors.toList());

// 收集到Set
Set<String> setResult = names.stream()
                            .filter(s -> s.length() > 2)
                            .collect(Collectors.toSet());

// 收集到Map(需要指定key和value的生成规则)
List<String> userInfo = new ArrayList<>();
Collections.addAll(userInfo, "张三-21-男", "李四-22-男");

Map<String, Integer> mapResult = userInfo.stream()
    .collect(Collectors.toMap(
        s -> s.split("-")[0],  // key:姓名
        s -> Integer.parseInt(s.split("-")[1])  // value:年龄
    ));

五、Stream 流的使用注意事项

  1. 流只能使用一次:一个 Stream 流对象只能执行一次终结操作,再次使用会抛出异常
  2. 不会修改源数据:Stream 流的操作不会改变原始集合或数组中的数据
  3. 惰性执行:中间操作只有在遇到终结操作时才会执行
  4. 并行流:对于大数据量,可以使用parallelStream()获取并行流提高处理效率

六、总结

Stream 流为 Java 集合和数组的处理提供了一种更优雅、更高效的方式。通过链式调用的中间操作和灵活的终结操作,我们可以用更少的代码实现复杂的数据处理逻辑。掌握 Stream 流的使用,不仅能提高开发效率,还能让代码更具可读性和可维护性。

无论是简单的过滤排序,还是复杂的数据转换和聚合,Stream 流都能胜任。在实际开发中,应充分利用 Stream 流的特性,写出更简洁、更现代的 Java 代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值