Stream流式使用

4 阅读3分钟

Stream流式使用

一、Stream是什么

Stream是支持顺序和并行聚合操作的元素序列。简单来说Stream 就像一条"流水线"——你把数据放上去,经过一道道工序(筛选、加工、转换),最后出来你想要的结果。

二、核心结构:

数据源 → 中间操作(懒执行)→ 终端操作(触发执行)。中间操作只是“记下工序”,不会真的跑,直到你调用终端操作(如 collect、forEach)才一次性执行。

结果 = 数据源.stream()          // 1. 拿到流
        .中间操作1()             // 2. 加工(可多个,懒执行)
        .中间操作2()
        .终端操作();             // 3. 触发执行,出结果

三、Strean的使用

1. 怎么拿到流(源头)

Stream 不能 new,只能从数据源获取:

list.stream()                    // 集合 → Stream<T>
Arrays.stream(array)             // 数组 → Stream<T>
Stream.of("a", "b", "c")         // 直接创建
IntStream.range(1, 10)           // 生成 1~9 的 int 流
Files.lines(Paths.get("f.txt"))  // 文件每行 → Stream<String>

2. 中间操作(返回 Stream,可链式)

这些方法定义在 Stream / IntStream 等接口上,懒执行:

filter(Predicate) — 筛选

map(Function) — 转换

flatMap(Function) — 转换并"摊平"(比如 List<List> → 一个流)

distinct() — 去重

sorted() / sorted(Comparator) — 排序

limit(n) / skip(n) — 取前 n 个 / 跳过前 n 个

peek(Consumer) — 偷看每个元素(调试用)

3. 终端操作(触发执行,返回结果)

collect(Collector) — 收集成 List/Set/Map 等

forEach(Consumer) — 遍历

count() — 计数

reduce(...) — 归约(求和、求积、拼字符串)

anyMatch / allMatch / noneMatch — 条件判断

findFirst / findAny — 找元素

min / max — 最值

sum() / average() — 只有 IntStream/LongStream/DoubleStream 才有

4.辅助工具

Collectors(java.util.stream.Collectors) 配合 collect 用,是静态工具类,不是流:

Collectors.toList()               // 收成 List
Collectors.toSet()                // 收成 Set
Collectors.toMap(k, v)            // 收成 Map
Collectors.groupingBy(...)        // 分组 → Map<K, List<T>>
Collectors.joining(",")           // 拼成字符串
Collectors.counting() / summingInt()  // 统计

三、最常见的使用场

  1. 筛选 + 收集(filter + collect) 从用户列表里找出成年人:
List<User> adults = users.stream()
    .filter(u -> u.getAge() >= 18)
    .collect(Collectors.toList());
  1. 转换(map) 把用户列表转成名字列表:
List<String> names = users.stream()
    .map(User::getName)
    .collect(Collectors.toList());
对象转另一个对象(如 User → UserDTO):
List<UserDTO> dtos = users.stream()
    .map(u -> new UserDTO(u.getId(), u.getName()))
    .collect(Collectors.toList());
  1. 筛选 + 转换 + 排序(链式)
List<String> result = users.stream()
    .filter(u -> u.getAge() >= 18)
    .map(User::getName)
    .sorted()
    .collect(Collectors.toList());
  1. 去重、取前几个、跳过
list.stream().distinct().collect(Collectors.toList());   // 去重
list.stream().limit(10).collect(Collectors.toList());    // 前 10 个
list.stream().skip(5).collect(Collectors.toList());      // 跳过前 5 个
  1. 判断条件(anyMatch / allMatch / noneMatch)
boolean hasAdult = users.stream().anyMatch(u -> u.getAge() >= 18);  // 有没有成年人
boolean allAdult = users.stream().allMatch(u -> u.getAge() >= 18);  // 是不是都成年
boolean noChild  = users.stream().noneMatch(u -> u.getAge() < 18);  // 有没有未成年
  1. 找元素(findFirst)
Optional<User> first = users.stream()
    .filter(u -> u.getAge() > 30)
    .findFirst();

// Optional 要这样取值,避免空指针
String name = first.map(User::getName).orElse("无");
  1. 统计:计数、求和、最值
long count = users.stream().filter(u -> u.getAge() >= 18).count();

// 求和/平均/最值,用 mapToInt 转成 IntStream 更方便
int totalAge = users.stream().mapToInt(User::getAge).sum();
double avgAge = users.stream().mapToInt(User::getAge).average().orElse(0);
Optional<User> oldest = users.stream().max(Comparator.comparing(User::getAge));
  1. 分组(groupingBy,业务里超常用) 按城市给用户分组:
Map<String, List<User>> byCity = users.stream()
    .collect(Collectors.groupingBy(User::getCity));

分组后统计每组人数:

Map<String, Long> cityCount = users.stream()
    .collect(Collectors.groupingBy(User::getCity, Collectors.counting()));
  1. 收成 Map(toMap) id → User 的映射:
Map<Long, User> idMap = users.stream()
    .collect(Collectors.toMap(User::getId, u -> u));

// 如果 key 可能重复,要加合并函数,否则会抛异常
Map<String, User> nameMap = users.stream()
    .collect(Collectors.toMap(User::getName, u -> u, (a, b) -> a));
  1. 拼字符串(joining)
String names = users.stream()
    .map(User::getName)
    .collect(Collectors.joining(", ", "[", "]"));  // 结果形如 [张三, 李四]
  1. 归约(reduce) 求所有年龄之和(也可以用 mapToInt().sum()):
int sum = users.stream()
    .map(User::getAge)
    .reduce(0, Integer::sum);
  1. flatMap 摊平嵌套集合 比如每个用户有多个订单,想拿到所有订单:
List<Order> allOrders = users.stream()
    .flatMap(u -> u.getOrders().stream())
    .collect(Collectors.toList());