主题
界面
主题
Markdown 是技术工作的通用书写格式:README、Issue、Pull Request 描述、代码注释、技术笔记、本知识库的全部内容,都用它。
本节不只讲语法(语法十分钟就能学完),重点讲技术文档的书写习惯——写什么、不写什么、怎么让三个月后的自己看得懂。
完成本节后,你应该能够:
无。会打字就能开始。
技术文档有两个消费者:别人和三个月后的你自己。
只写给自己看时,人往往会写成这样:
今天搞了半天,那个空指针终于好了,是因为 map 里没有那个 key。一个问题:三个月后你还记得是哪个 map、哪个 key、改了什么吗? 而且这个笔记搜不到——你搜索"NullPointerException"匹配不上这句话(因为当时你写的是"空指针")。
再看一份能复用的版本:
## 现象
查询用户详情接口偶发 NPE,订单列表页刷新 10 次出现 1 次。
## 原因
`UserService.getDetail` 里 `map.get(userId)` 返回 null,直接调用了 `.getName()`。
## 修复
改用 `Optional.ofNullable(...).map(...)`,并在接口层返回 404 而不是 500。
## 验证
补充 3 个单元测试(key 不存在 / value 为 null / 正常),接口回归 20 次无异常。差别不在文采,而在结构:现象、原因、修复、验证四段固定,写的人不用想"该怎么记",看的人能直接跳到关心的段落。
# 一级标题(一篇文档只用一个)
## 二级标题
- 无序列表
1. 有序列表
- [ ] 待办项
- [x] 已完成项
`行内代码` 与**加粗**、*斜体*
> 引用:常用于强调结论或引用规范
```java
// 代码块一定要写语言,这样才有语法高亮
System.out.println("Hello");
```
| 列 | 说明 |
| --- | --- |
| 表格 | 对比信息时最清楚 |
[链接文字](https://example.com)| 要素 | 作用 | 判断标准 |
|---|---|---|
| 结论先行 | 让人三秒知道结果 | 开头一段能不能独立看懂 |
| 可搜索的关键词 | 未来能找到它 | 是否包含异常类名、方法名、错误码 |
| 可执行的步骤 | 别人能复现 | 是否写了命令、参数、环境 |
| 自己的判断 | 体现你理解了 | 有没有"为什么这么修"而不是只抄命令 |
| 反模式 | 问题 |
|---|---|
| 截图代替文字 | 不可搜索、不可复制、不可 diff |
| 整段粘贴日志 | 关键信息被淹没,应节选 + 标注 |
| 只贴解决方案不写问题 | 三个月后不知道它在解决什么 |
标题层级乱跳(# 直接到 ####) | 目录结构错乱,读者迷路 |
| 代码块不写语言 | 没有高亮,阅读成本上升 |
你正在读的每节课都遵循同一套结构,这就是"文档模板"的价值:结构固定后,注意力就能放在内容上。
本节定位 → 学习目标 → 前置知识检查 → 为什么需要 → 核心概念
→ 递进示例 → 完整可运行代码 → Debug 观察点 → 常见错误
→ 动手实验 → 练习题 → 参考答案 → 掌握标准 → 扩展资源 → 下一步# S1-017 HashMap 学习笔记
## 一句话结论
HashMap 用数组 + 链表/红黑树实现,查找平均 O(1);扩容阈值 = 容量 × 0.75。
## 我踩的坑
自定义对象做 key 时没重写 equals/hashCode,`get` 永远返回 null。
## 关键代码
```java
record GoodKey(String id) {} // record 自动生成 equals/hashCode红黑树化的阈值为什么是 8 和 6(记下来,学到 JVM 时回看)
最后一段"还没搞懂"是关键——**把疑问显性记录下来**,比假装都懂了有价值得多。
### 6.2 业务示例:Bug 记录模板
```markdown
## 环境
JDK 21 / Spring Boot 3.2 / MySQL 8
## 现象
并发提交订单时,偶发 `Duplicate entry` 主键冲突。
## 复现步骤
1. 用 JMeter 以 50 并发调用 `/order`
2. 观察数据库日志,约 1% 请求报主键冲突
## 定位过程
查看主键生成逻辑,发现用的是"查最大 ID + 1"而非数据库自增/序列。
## 根因
并发下两个请求查到同一个最大 ID,各自 +1 后写入,撞车。
## 修复与验证
改用分布式 ID 生成器;补充并发测试用例(50 并发 1000 次请求无冲突)。这份记录的价值不在"修复了 bug",而在于下次遇到类似现象时能 5 秒定位。
今天学了 Stream,挺好用的,filter 和 map 都试了一下。三个月后你要用它时,这份笔记提供不了任何信息——没有 API 清单、没有代码、没有坑点、没有适用场景。
本节无 Java 代码。作为替代,请把下面这份模板保存到你的笔记工具里,作为以后写 Bug 记录的标准骨架:
## 现象
(一句话说清"什么操作 → 什么结果",包含完整异常类名便于搜索)
## 影响范围
(哪些功能、多少用户、是否阻塞)
## 复现步骤
1. 环境:
2. 操作:
3. 期望结果:
4. 实际结果:
## 定位过程
(用过什么命令、看了哪些日志、排除了哪些可能)
## 根因
(一句话结论 + 关键代码片段)
## 修复与验证
(改了什么、怎么验证、补了什么测试)没有调试器可开,但有一个判断练习:打开你半年内写过的一份笔记,只看前 30 秒,问自己三个问题:
三个都是"是",说明你的文档习惯已经合格。
```
List<String> list = new ArrayList<>();
```没有语言标记就没有高亮。修复:写成 ```java。
# 标题
#### 直接跳到四级修复:逐级递进(# → ## → ###),否则生成的目录会错乱。
| 字符没转义 单元格内容里的 | 会被当成列分隔符。修复:写成 \|,或用行内代码包起来。
目标:产出两份可复用的文档。
步骤:
docs: ...;验收方式:第 4 步能读懂,说明记录合格。
扩展任务:给笔记加一个"关键词行"(如 #NullPointerException #HashMap #并发),方便日后搜索——这是很多人的笔记"写得多但找不到"的原因。
基础题
# 直接跳到 ####。(对 / 错)改写题
今天用 for-each 删 list 里的元素报错了,后来换了 removeIf 就好了。综合任务
提示 1(方向):第 4 题的关键是把"报错"变成"完整异常类名 + 代码行 + 原因 + 修复"。
提示 2(关键点):第 5 题可以直接借鉴 S0-002 IDEA 与项目创建 里的环境检查清单。
提示 3(接近答案):第 4 题的合格答案里应该出现 ConcurrentModificationException 这个完整类名——因为半年后你是靠它搜索的。
- [ ] 未完成 与 - [x] 已完成。## 现象
遍历 `ArrayList` 时调用 `list.remove(item)`,抛出 `ConcurrentModificationException`。
## 原因
for-each 底层使用迭代器,遍历过程中直接修改集合会让迭代器检查失败。
## 修复
1. 用 `list.removeIf(item -> 条件)`;
2. 或改用显式 `Iterator` 并调用 `iterator.remove()`。
## 注意
删除倒数第二个元素时可能不抛异常(迭代已结束,没有机会检查),所以这个 bug 容易偶发。关键改进:写上了完整异常类名(可搜索)、触发条件(可判断是否同因)、两种修复方案。
参考结构:
# 我的 Java 学习环境
| 项目 | 版本 / 位置 |
| --- | --- |
| 操作系统 | Windows 11 |
| JDK | OpenJDK 25.0.2 LTS(Microsoft) |
| JAVA_HOME | C:\Program Files\Microsoft\jdk-25.0.2.10-hotspot |
| 编译目标 | Java 21(`--release 21`) |
| IDE | IntelliJ IDEA Community |
| Maven | 由 `labs/mvnw` 提供,无需本机预装 |
## 环境检查命令
```powershell
java -version
javac -version
echo $env:JAVA_HOME
cd labs && ./mvnw -v项目内 labs/.mvn/settings.xml 已配置阿里云镜像,无需修改用户级 settings.xml。
cd labs
./mvnw -pl start compile # 编译指定模块
./mvnw test # 全量测试
./mvnw -pl testing-unit test -Dtest=UserServiceTest # 跑单个测试类
这份文档的实际价值:换电脑或重装系统时,照着它 10 分钟能恢复开发环境。《如何向 AI 提问与审核 AI 代码》 会讲清 AI 协作的边界与审核方法——AI 生成的代码,最终要由你签字。
无,可直接开始
暂无