小易说IT 小易说IT

Java Stream 流基础入门

Stream 是 Java8 新增,用来对集合 / 数组做链式、声明式数据处理(过滤、映射、排序、去重、聚合等),不是数据结构,不存储数据,一次性使用,用完就关闭。

核心一句话:先获取流 → 中间操作(加工,返回新流,懒加载) → 终端操作(触发执行,关闭流)

一、入门三步总流程

  1. 创建 Stream(获取流)

  2. 中间操作(链式加工,lazy 懒加载,不执行)

  3. 终端操作(触发计算,关闭流,只能有一个)

二、1. 创建 Stream(4 种常用方式)

import java.util.*;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        // ① Collection 集合(List/Set)直接 stream() 【最常用】
        List<String> list = Arrays.asList("A", "B", "C");
        Stream<String> stream1 = list.stream();

        // ② 数组:Arrays.stream(数组)
        String[] arr = {"a", "b", "c"};
        Stream<String> stream2 = Arrays.stream(arr);

        // ③ Stream.of() 直接传入多个元素
        Stream<String> stream3 = Stream.of("x", "y", "z");

        // ④ 创建空流 / 无限流(了解即可)
        Stream<String> emptyStream = Stream.empty();
        // Stream.iterate(1, n -> n + 2); // 无限流,一定要配合 limit 截断
    }
}

区分:stream() 顺序流、parallelStream() 并行流(多线程,数据无序)

三、2. 中间操作(返回 Stream,懒加载,可链式叠加)

中间操作不会真正执行,只有遇到终端操作才一起执行。 常用中间方法:

方法

作用

filter(Predicate)

过滤,保留满足条件元素

map(Function)

映射转换,一个元素 → 一个元素(类型转换)

flatMap(Function)

扁平化,一个元素拆成流(拆分集合)

sorted()

自然排序 /sorted (Comparator) 自定义排序

distinct()

去重(依赖 equals/hashCode)

limit(n)

取前 n 个

skip(n)

跳过前 n 个

peek(Consumer)

调试打印,不改变流(看中间值)

示例:

List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8);

nums.stream()
    .filter(n -> n % 2 == 0)       // 过滤偶数:2,4,6,8
    .map(n -> n * 10)              // 每个 ×10:20,40,60,80
    .sorted(Comparator.reverseOrder()) // 倒序:80,60,40,20
    .limit(3);                     // 取前3个:80,60,40
// 到这里只是定义流水线,还没执行!

四、3. 终端操作(触发执行,关闭流,只能一个)

终端操作执行后,流就失效,不能再继续调用流方法。

分类

方法

作用

收集

collect(Collectors.toList())

转为 List,最常用

遍历

forEach(Consumer)

逐个遍历输出

匹配

anyMatch / allMatch / noneMatch

是否任意 / 全部 / 没有匹配,返回 boolean

查找

findFirst / findAny

获取第一个 / 任意元素,返回 Optional

聚合

count()、max()、min()

计数、最大、最小

规约

reduce

累加、求和、自定义聚合

接上上面例子,加上终端操作:

List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8);

List<Integer> res = nums.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * 10)
    .sorted(Comparator.reverseOrder())
    .limit(3)
    .collect(Collectors.toList()); // ✅ 终端操作,真正执行

System.out.println(res); // [80, 60, 40]

其他终端示例

// 遍历
nums.stream().filter(n->n>3).forEach(System.out::println);

// 计数
long count = nums.stream().filter(n->n%2==0).count();

// 是否存在大于5的数
boolean has = nums.stream().anyMatch(n -> n >5);

// 求和(reduce)
Integer sum = nums.stream().reduce(0, Integer::sum);

五、完整入门示例(实体类场景,开发高频)

import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Data
@AllArgsConstructor
class User{
    private String name;
    private Integer age;
}

public class UserStreamDemo {
    public static void main(String[] args) {
        List<User> userList = Arrays.asList(
                new User("张三",18),
                new User("李四",22),
                new User("王五",16),
                new User("赵六",25)
        );

        // 需求:筛选年龄>=18,提取姓名,收集成List
        List<String> nameList = userList.stream()
                .filter(user -> user.getAge() >= 18)  // 中间:过滤成年人
                .map(User::getName)                   // 中间:只拿名字
                .collect(Collectors.toList());       // 终端:收集

        System.out.println(nameList); // [张三,李四,赵六]
    }
}

六、重要规则(新手坑)

  1. 流只能消费一次:终端执行完,流就关闭,重复调用会抛 IllegalStateException: stream has already been operated upon or closed

Stream<Integer> s = nums.stream();
s.collect(Collectors.toList());
s.filter(x->x>1); // ❌ 报错!流已经关闭
  1. 中间操作懒加载:没有终端操作,中间代码完全不会跑

  2. 不修改原集合:Stream 处理是新建结果,原始 List 不变

  3. map 一对一;flatMap 适合拆分嵌套集合(比如 List<List<String>> 摊平成一维)

七、常用简写:方法引用

// 等价写法
.map(user -> user.getName())
.map(User::getName)

本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/java-stream-basics-guide

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/