Stream 是 Java8 新增,用来对集合 / 数组做链式、声明式数据处理(过滤、映射、排序、去重、聚合等),不是数据结构,不存储数据,一次性使用,用完就关闭。
核心一句话:先获取流 → 中间操作(加工,返回新流,懒加载) → 终端操作(触发执行,关闭流)
一、入门三步总流程
创建 Stream(获取流)
中间操作(链式加工,lazy 懒加载,不执行)
终端操作(触发计算,关闭流,只能有一个)
二、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,懒加载,可链式叠加)
中间操作不会真正执行,只有遇到终端操作才一起执行。 常用中间方法:
示例:
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. 终端操作(触发执行,关闭流,只能一个)
终端操作执行后,流就失效,不能再继续调用流方法。
接上上面例子,加上终端操作:
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); // [张三,李四,赵六]
}
}
六、重要规则(新手坑)
流只能消费一次:终端执行完,流就关闭,重复调用会抛
IllegalStateException: stream has already been operated upon or closed
Stream<Integer> s = nums.stream();
s.collect(Collectors.toList());
s.filter(x->x>1); // ❌ 报错!流已经关闭
中间操作懒加载:没有终端操作,中间代码完全不会跑
不修改原集合:Stream 处理是新建结果,原始 List 不变
map一对一;flatMap适合拆分嵌套集合(比如List<List<String>>摊平成一维)
七、常用简写:方法引用
// 等价写法
.map(user -> user.getName())
.map(User::getName)
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问