《Java 编程入门》附录 D 常见编译与运行错误
按报错关键词整理 Java 入门阶段最常见的编译与运行问题:找不到符号、类型不兼容、找不到主类、类版本不匹配、NoSuchMethodError、空指针、数组越界、并发修改、编码乱码、Maven 依赖冲突、jar 无法运行、端口占用等,每条给出典型报错、原因、排查步骤与修复示例。
tag
按报错关键词整理 Java 入门阶段最常见的编译与运行问题:找不到符号、类型不兼容、找不到主类、类版本不匹配、NoSuchMethodError、空指针、数组越界、并发修改、编码乱码、Maven 依赖冲突、jar 无法运行、端口占用等,每条给出典型报错、原因、排查步骤与修复示例。
让同一 commit 在任何机器上产出相同字节:锁定 Maven 生命周期插件版本,设置 project.build.outputTimestamp,连续两次 clean package 比较 jar 的 SHA-256,并说明 SNAPSHOT、时区与本地缓存会怎样破坏可复现性。
把 JDK 21 到 25 的正式特性与预览特性分开列清楚:21 的虚拟线程、记录模式、switch 模式匹配,22 的 FFM API 与未命名变量,23 的 Markdown 文档注释与分代 ZGC 默认,24 的 Class-File API 与 Stream Gatherers,25 的 Scoped Values、模块导入声明、紧凑源文件、灵活构造器与紧凑对象头,并给出迁移建议。
把散落在子模块里的版本号收回父 POM:用 dependencyManagement 与 Jackson BOM 统一版本,用 runtime、test 作用域收紧依赖,再用 Enforcer 的 dependencyConvergence 抓出 Javalin 与 Jedis 带来的真实冲突并收敛。
按包梳理 java.base 与常用 JDK 模块:java.lang、java.util、java.io、java.nio.file、java.time、java.net.http、java.util.concurrent、java.util.regex 等各自负责什么、关键类有哪些、什么时候该用,并给出按任务选包的速查表。
把卷一的单模块 library 拆成 domain、persistence、web、app、integration-tests 五个模块:先按变化频率和依赖方向划边界,再写出可编译的父 POM、子模块 POM 与最小骨架,最后用 Maven reactor 和依赖树验证拆分结果。
把《Java 编程入门》涉及的语法压缩成一页可查的速查表:基本类型、变量、运算符、控制流、方法、类与接口、record/enum/sealed、泛型、集合、Stream、异常、NIO、java.time、正则,以及常用的 javac/java/mvn 命令,每项都配最小示例。
不引入任何 Web 框架,用 JDK 自带的 com.sun.net.httpserver 把 LibraryService 暴露成 REST:手写扁平 JSON、实现 GET /books、POST /books、POST /loans、POST /returns,并用 curl 验证 201、409 等真实响应。
给 library 接上存储和交互:用 LibraryRepository 接口隔离存储,用 TreeMap 与活动借阅表实现内存仓储,再让 CommandParser 解析 add、list、borrow、return、search、quit 六个命令,最后用真实终端会话跑通借阅与归还。
把前 17 章的能力收束成一个完整项目:先划清 library 的需求边界,再用 Book、Member、Loan 三个 record 和 LibraryService 的借阅、归还方法,把「一本书同时只能借给一个人、借期 14 天、逾期按天计费」写成可执行的领域规则。
把 library 的构建从「我这儿能打包」推进到「谁都能复现」:用 outputTimestamp 固定 jar 条目时间,用固定依赖、BOM 和 enforcer 禁止动态版本,再用 sha256、dependency:tree 与离线构建验证发布产物。
把 library 的 class 文件打成可直接运行的 jar:读懂 jar 与 MANIFEST.MF,用 maven-jar-plugin 写 Main-Class,比较依赖复制与 maven-shade-plugin 的取舍,再补上 module-info、jar --describe-module、jdeps 与 jlink 的完整命令和真实输出。
从 library 的 JUnit 测试依赖出发,讲清 Maven 坐标、传递依赖与 compile、test、provided、runtime 四种作用域的实际影响;再用真实的依赖树、冲突裁决记录和 NoClassDefFoundError,说明最近优先、dependencyManagement 与 BOM 的用法。
测试写得吃力,往往不是测试技巧问题,而是设计没有留缝。本节从 library 的 Clock、Supplier、仓储接口出发,讲清构造器注入、纯函数、窄接口与确定性输入四个杠杆,并给出可复用的测试分层、真实 mvn test 输出与反模式清单。
把 Dummy、Stub、Fake、Spy、Mock 五种替身放回 library 的仓储接口上:用 Stub 制造「书不存在」,用 Fake 验证借还流程,用记录型 Mock 检查 save 调用次数,并说明什么时候不该验证交互、如何避免测试变脆。
从手工跑 main 验证借阅规则的痛点出发,给出 Maven 引入 JUnit 5 的最小 pom、断言与异常断言、测试生命周期、嵌套与参数化测试;再用 library 的 LoanPolicyTest 和真实 mvn test 输出,说明一条测试应该验证什么。
从 ISBN 的连字符、空格和校验位讲起,区分 matches 与 find、分组与命名分组、replaceAll 的替换陷阱;再用 library 的 ISBN 校验和检索语法解析,配真实输出说明正则能做什么、不能做什么,以及灾难性回溯的边界。
从借阅凭证和馆藏报表出发,讲清 String 不可变与字符串池、字符串拼接的真正代价、StringBuilder 的使用边界,以及文本块的缩进规则和 formatted;最后用 library 的凭证与报表代码展示什么时候该拼接、什么时候该换模板。
把 java.time 拆成日期、时刻、时区三层,用 library 的借期 14 天、续借、逾期罚金串起 LocalDate、Instant、ZonedDateTime、Duration、Period 与 DateTimeFormatter,并解释夏令时缺口、重叠时刻和 YYYY 与 yyyy 的真实差别。
从按年月归档的 CSV 目录出发,讲清 Files.walk 的 maxDepth 语义、Files.find 的属性过滤、walkFileTree 的访问者模式与 glob 匹配;再用 WatchService 监听 inbox,给出去抖、过滤临时文件、幂等导入和 key.reset 的完整做法。