Java 入门教程(十二):Stream API 与综合实战
1722 字
9 分钟
Java 入门教程(十二):Stream API 与综合实战
- 1Java 入门教程(一):JDK、IDEA 与第一个程序
- 2Java 入门教程(二):语法基础与运算符
- 3Java 入门教程(三):流程控制
- 4Java 入门教程(四):方法与数组
- 5Java 入门教程(五):面向对象(上)——类与封装
- 6Java 入门教程(六):面向对象(下)——继承、多态与接口
- 7Java 入门教程(七):核心类库——String、包装类与常用工具
- 8Java 入门教程(八):集合框架
- 9Java 入门教程(九):异常处理
- 10Java 入门教程(十):文件 IO 与 NIO
- 11Java 入门教程(十一):多线程与 Lambda
- 12Java 入门教程(十二):Stream API 与综合实战本文
本篇目标
双主题收官:Stream API(Java 8 最优雅的数据处理武器)+ 综合实战(用全系列知识写一个学生管理系统)。
一、Stream API
是什么
Stream 是数据流水线:数据源 → 中间操作(惰性)→ 终端操作(触发)。它不存数据、不改源,只声明”怎么处理”:
import java.util.List;import java.util.stream.Collectors;
List<String> names = List.of("小明", "小红", "小刚", "小美", "小强");
List<String> result = names.stream() // ① 建流 .filter(n -> n.startsWith("小")) // ② 中间操作:过滤(还没执行!) .map(String::length) // ③ 中间操作:变换 .collect(Collectors.toList()); // ④ 终端操作:触发整条流水线创建流的三种方式
// 集合 → stream()List<Integer> list = List.of(1, 2, 3);list.stream();
// 数组 → Arrays.streamint[] arr = {1, 2, 3};Arrays.stream(arr).sum();
// 静态工厂 → Stream.of / generate / iterateStream<Integer> s1 = Stream.of(1, 2, 3);Stream<Integer> s2 = Stream.iterate(1, n -> n * 2).limit(10); // 1,2,4,8...1024中间操作全家桶
List<Integer> nums = List.of(5, 3, 8, 1, 3, 9, 2);
// filter:过滤nums.stream().filter(n -> n > 3).forEach(System.out::println); // 5 8 9
// map:一对一变换nums.stream().map(n -> n * n).forEach(System.out::println); // 25 9 64 ...
// distinct / sorted / limit / skipnums.stream().distinct().sorted().limit(3).toList(); // [1, 2, 3]nums.stream().sorted(Comparator.reverseOrder()).skip(1).toList(); // [8,5,3,3,2]
// flatMap:一对多展开(流中流拍扁)List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4));nested.stream().flatMap(List::stream).toList(); // [1,2,3,4]
// peek:偷看(调试利器)nums.stream().peek(n -> System.out.println("处理中: " + n)) .map(n -> n + 1).toList();终端操作全家桶
List<Integer> nums = List.of(5, 3, 8, 1, 9);
// —— 归约计算 ——nums.stream().count(); // 5nums.stream().mapToInt(Integer::intValue).sum();// 26(先转 IntStream 性能更好)nums.stream().max(Integer::compareTo); // Optional[9]nums.stream().min(Integer::compareTo); // Optional[1]nums.stream().filter(n -> n > 3).findFirst(); // Optional[5]nums.stream().filter(n -> n > 3).findAny();
// —— 匹配判断 ——nums.stream().allMatch(n -> n > 0); // true(全部满足)nums.stream().anyMatch(n -> n > 8); // true(任一满足)nums.stream().noneMatch(n -> n < 0); // true(都不满足)
// —— 遍历 ——nums.stream().forEach(System.out::println);Collectors:收集器(最强大)
List<Student> st = List.of( new Student("小明", "一班", 90), new Student("小红", "二班", 85), new Student("小刚", "一班", 92), new Student("小美", "二班", 78));
// toList / toSetList<String> names = st.stream().map(s -> s.name).toList(); // Java 16+ 直接 toList
// joining:字符串拼接String all = st.stream().map(s -> s.name) .collect(Collectors.joining(", ", "[", "]")); // [小明, 小红, 小刚, 小美]
// groupingBy:分组(Map<String, List<Student>>)Map<String, List<Student>> byClass = st.stream() .collect(Collectors.groupingBy(s -> s.clazz));
// 分组 + 下游统计Map<String, Long> countByClass = st.stream() .collect(Collectors.groupingBy(s -> s.clazz, Collectors.counting()));// {一班=2, 二班=2}
Map<String, Double> avgByClass = st.stream() .collect(Collectors.groupingBy(s -> s.clazz, Collectors.averagingDouble(s -> s.score)));// {一班=91.0, 二班=81.5}
Map<String, Optional<Student>> topByClass = st.stream() .collect(Collectors.groupingBy(s -> s.clazz, Collectors.maxBy(Comparator.comparing(s -> s.score))));
// partitioningBy:按布尔分两组Map<Boolean, List<Student>> passFail = st.stream() .collect(Collectors.partitioningBy(s -> s.score >= 60));
// toMap:收集成 MapMap<String, Integer> scoreMap = st.stream() .collect(Collectors.toMap(s -> s.name, s -> s.score, (a, b) -> b)); // 第3参处理键冲突并行流一行提速
long sum = java.util.stream.IntStream.rangeClosed(1, 100_000_000) .parallel() // 一行变多核并行 .sum();// 适合:数据量大 + 元素计算重;小数据反而更慢(线程切换开销)二、综合实战:学生管理系统
全系列知识总集成:OOP + 集合 + 异常 + IO + 多线程。
// ===== StudentSystem.java 完整可编译 =====import java.io.IOException;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.StandardOpenOption;import java.util.*;import java.util.stream.Collectors;
public class StudentSystem {
// —— 数据模型(record + 封装)—— record Student(String id, String name, String className, double score) { String toCsv() { return String.join(",", id, name, className, String.valueOf(score)); } static Student fromCsv(String line) { String[] p = line.split(",", -1); if (p.length != 4) return null; try { return new Student(p[0], p[1], p[2], Double.parseDouble(p[3])); } catch (NumberFormatException e) { return null; } } }
// —— 业务异常(第九篇)—— static class SysException extends RuntimeException { SysException(String msg) { super(msg); } }
// —— 服务层:集合 + Stream(第八篇 + 本篇)—— static class Service { private final Map<String, Student> data = new LinkedHashMap<>(); private final Path file = Path.of("students.csv");
Service() { load(); }
Student add(String name, String className, double score) { if (score < 0 || score > 100) throw new SysException("成绩必须在 0~100: " + score); String id = "S" + (data.size() + 1001); Student s = new Student(id, name, className, score); data.put(id, s); save(); return s; }
void remove(String id) { if (data.remove(id) == null) throw new SysException("学号不存在: " + id); save(); }
List<Student> ranking() { return data.values().stream() .sorted(Comparator.comparingDouble(Student::score).reversed()) .collect(Collectors.toList()); }
Map<String, Double> classAverages() { return data.values().stream() .collect(Collectors.groupingBy(Student::className, Collectors.averagingDouble(Student::score))); }
List<Student> search(String kw) { return data.values().stream() .filter(s -> s.name().contains(kw) || s.id().contains(kw)) .collect(Collectors.toList()); }
// —— 持久化(第十篇)—— private void save() { try { Files.write(file, data.values().stream().map(Student::toCsv).toList(), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { throw new SysException("保存失败: " + e.getMessage()); } }
private void load() { if (!Files.exists(file)) return; try { Files.readAllLines(file, StandardCharsets.UTF_8).stream() .map(Student::fromCsv) .filter(Objects::nonNull) .forEach(s -> data.put(s.id(), s)); } catch (IOException e) { System.err.println("加载失败: " + e.getMessage()); } } }
// —— 控制台交互(流程控制 + 异常处理)—— public static void main(String[] args) { Service svc = new Service(); Scanner sc = new Scanner(System.in);
System.out.println("=== 学生管理系统 ==="); System.out.println("add 姓名 班级 成绩 | del 学号 | rank | stat | search 关键词 | list | quit");
while (true) { System.out.print("\n> "); String line = sc.nextLine().trim(); if (line.isEmpty()) continue; String[] p = line.split("\\s+"); String cmd = p[0];
try { switch (cmd) { case "quit" -> { System.out.println("再见!"); return; } case "add" -> { if (p.length < 4) throw new SysException("用法: add 姓名 班级 成绩"); Student s = svc.add(p[1], p[2], Double.parseDouble(p[3])); System.out.println("✅ 已添加 " + s.id() + " " + s.name()); } case "del" -> { svc.remove(p[1]); System.out.println("🗑 已删除"); } case "rank" -> svc.ranking().forEach(s -> System.out.printf(" %-6s %-6s %-4s %.1f%n", s.id(), s.name(), s.className(), s.score())); case "stat" -> { svc.classAverages().forEach((cls, avg) -> System.out.printf(" %s: 平均 %.1f%n", cls, avg)); System.out.println(" 全员均分: " + svc.ranking().stream() .mapToDouble(Student::score).average().orElse(0)); } case "search" -> svc.search(p[1]).forEach(s -> System.out.println(" " + s)); case "list" -> svc.ranking().forEach(s -> System.out.println(" " + s)); default -> System.out.println("未知命令"); } } catch (SysException e) { System.out.println("❌ " + e.getMessage()); } catch (Exception e) { System.out.println("输入格式错误: " + e.getMessage()); } } }}运行演示:
> add 小明 一班 90✅ 已添加 S1001 小明> add 小红 二班 85✅ 已添加 S1002 小红> rank S1001 小明 一班 90.0 S1002 小红 二班 85.0> stat 一班: 平均 90.0 二班: 平均 85.0> del S1002🗑 已删除> quit涉及知识清单:record(现代数据类)、LinkedHashMap、Stream 排序/分组/统计、Collectors 全家桶、自定义异常、Files 持久化、switch 表达式、Scanner 交互。这就是”全系列合体”。
三、系列总结
| 篇 | 主题 | 关键收获 |
|---|---|---|
| 1 | 环境与第一个程序 | JDK/JVM、IDEA、main 结构 |
| 2 | 语法与运算符 | 八大类型、转换陷阱、printf |
| 3 | 流程控制 | switch 表达式、标签跳转 |
| 4 | 方法与数组 | 重载、值传递本质、Arrays 工具 |
| 5 | 面向对象(上) | 封装、JavaBean、static、包与权限 |
| 6 | 面向对象(下) | 继承、多态、接口、equals/hashCode |
| 7 | 核心类库 | String 不可变、包装类、BigDecimal、日期 |
| 8 | 集合框架 | List/Set/Map、merge 计数、Comparator |
| 9 | 异常处理 | 受检/非受检、try-with-resources |
| 10 | 文件 IO | Files 一行流、编码、CSV 持久化 |
| 11 | 多线程与 Lambda | 线程池、synchronized、函数式接口 |
| 12 | Stream 与实战(本篇) | 流水线、Collectors、综合项目 |
下一步方向:Spring Boot 后端开发、Android 应用、大数据生态(Hadoop/Spark 均是 Java 系)、或深入 JVM 原理。做出项目欢迎投稿本站!
小练习(毕业设计)
- 学生系统加”修改成绩”与”按班级删除”命令
- 把存储从 CSV 升级为 JSON(手写简易序列化或引入 Gson)
- 加”异步导出报表”功能:线程池执行导出,导出完成后提示(多线程 + Future)
- 用 Stream 一行实现:求数组中”偶数的平方的平均值”
- (三系列横向)用 Python 与 C++ 各重写一个命令行 Todo,对比三种语言的代码量与思路差异
本系列为 Cyber先锋社原创教程,共 12 篇完结。至此本站 Python(11篇)/ C++(12篇)/ Java(12篇)三大入门系列全部完结,欢迎在留言板晒毕业设计!
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Java 入门教程(十二):Stream API 与综合实战
https://www.cyberpioneer.club/posts/java-tutorial-12/相关文章智能推荐
1
Java 入门教程(四):方法与数组
Java 教程掌握 Java 方法定义与重载、可变参数、值传递本质、数组全操作(声明/遍历/工具类 Arrays/二维数组)、命令行参数与 main 签名,附数组统计与矩阵转置实战。
2
Java 入门教程(二):语法基础与运算符
Java 教程详解 Java 基本语法:注释、变量与常量、八种基本类型与类型转换规则、七类运算符、Scanner 输入进阶与 printf 格式化,配典型陷阱与对照示例。
3
Java 入门教程(一):JDK、IDEA 与第一个程序
Java 教程进入 Java 的世界:理解"一次编写,到处运行"的原理、安装 JDK 与 IDEA、解剖第一个程序的结构、掌握变量与数据类型。企业级开发语言的起点。
4
Java 入门教程(三):流程控制
Java 教程完整讲解 Java 分支(if/switch 语句与 switch 表达式)、三种循环、break/continue 带标签跳转、嵌套循环经典练习(九九表/质数/图形/水仙花),覆盖 Java 14+ 增强 switch 新语法。
5
C++ 入门教程(十二):异常处理、文件 IO 与综合实战
C++ 教程系列收官:C++ 异常体系(throw/try/catch、标准异常层级、自定义异常、 noexcept)、文件流读写(ifstream/ofstream/stringstream)、通讯录项目综合实战与系列总结。
随机文章随机推荐



