覆盖 JVM 调优、Lambda、IO 模型、缓存、Spring 事务、注解、字符串、容器、异步、GC、文件操作等
1. soft 引用 vs weak 引用 vs phantom 引用(精简两两组对比,本表区分三者)
表格
| 对比维度 | SoftReference 软引用 | WeakReference 弱引用 | PhantomReference 虚引用 |
|---|---|---|---|
| 回收触发 | 堆内存不足 GC 才回收 | 下一次 GC 直接回收 | 对象真正销毁前入队列 |
| get () 取值 | 可正常获取对象 | GC 后 get 返回 null | get 永远返回 null |
| 适用场景 | 大图片、可重建缓存 | 临时缓存、WeakHashMap | 堆外内存、资源释放监控 |
| 内存缓解 | 能有效防止 OOM | 无法缓解内存溢出 | 不持有对象,不减少内存占用 |
2. Spring 编程式事务 vs 声明式 @Transactional 事务
表格
| 对比维度 | 编程式事务 (TransactionTemplate) | 声明式 @Transactional |
|---|---|---|
| 代码侵入 | 高,业务代码嵌入事务模板 | 低,注解无业务侵入 |
| 粒度控制 | 可精准控制局部代码块事务 | 粒度为整个 public 方法 |
| 回滚规则 | 代码手动控制 commit/rollback | 注解配置回滚异常规则 |
| 异常感知 | 代码内可灵活判断分支回滚 | 统一全局规则,分支难自定义 |
| 适用场景 | 复杂多分支、动态事务逻辑 | 绝大多数常规 CRUD 业务 |
3. synchronized 偏向锁 vs 轻量级锁 vs 重量级锁
| 对比维度 | 偏向锁 | 轻量级锁 | 重量级锁 || ---- | ---- | ---- || 竞争场景 | 全程单线程无竞争 | 多线程交替执行,无并发争抢 | 同一时间多线程争抢锁 || 底层实现 | 标记位记录线程 ID,无 CAS 自旋 | CAS 自旋抢锁,无内核阻塞 | 操作系统内核互斥锁,线程阻塞 || 性能开销 | 几乎无消耗,最优 | 自旋消耗 CPU,无线程切换 | 上下文切换,开销极大 || 适用场景 | 单线程反复获取同一锁 | 低并发交替执行代码块 | 高并发激烈竞争场景 |
4. Stream filter + map vs map + filter
表格
| 对比维度 | 先 filter 后 map | 先 map 后 filter |
|---|---|---|
| 对象处理数量 | 过滤后再转换,减少 map 执行次数 | 所有元素全部转换,转换次数更多 |
| 性能表现 | 数据量大时性能更优 | 产生大量无用转换对象,GC 压力高 |
| 逻辑顺序 | 先过滤无效数据,再加工有效数据 | 全量加工再丢弃,浪费计算资源 |
| 推荐规范 | 业务优先使用先过滤后映射 | 仅特殊场景必须先转换再过滤 |
5. Stream findFirst() vs findAny()
表格
| 对比维度 | findFirst() | findAny() |
|---|---|---|
| 有序流行为 | 固定取第一个元素 | 随机返回任意匹配元素 |
| 并行流行为 | 依旧保证有序,性能损耗高 | 并行不保证顺序,执行更快 |
| 底层逻辑 | 有状态有序操作,需维护顺序 | 无状态,并行分片独立查找 |
| 业务场景 | 依赖数据顺序的业务 | 只需要任意一条匹配数据,追求并行性能 |
6. ArrayList ensureCapacity () vs 初始化指定容量 new ArrayList (n)
表格
| 对比维度 | new ArrayList<>(初始容量) | list.ensureCapacity(minCapacity) |
|---|---|---|
| 执行时机 | 集合创建时一次性分配数组 | 集合已存在,事后扩容预分配 |
| 扩容次数 | 创建即分配,全程无多次扩容 | 避免多次扩容复制数组 |
| 内存开销 | 启动直接占用对应容量数组 | 已有数组基础上扩容,临时双倍内存 |
| 适用场景 | 提前预知数据总量 | 集合中途追加大量数据,提前扩容优化 |
7. 字符缓冲 BufferedReader vs Scanner 读取文本
表格
| 对比维度 | BufferedReader | Scanner |
|---|---|---|
| 读取速度 | 底层缓冲区,读取大文件极快 | 封装复杂,大量文本性能差 |
| 换行分割 | readLine () 直接读取整行 | 需自定义分隔符处理换行 |
| 数据解析 | 仅原始字符串,需手动转数字 | 内置 nextInt/nextDouble 自动解析 |
| 内存占用 | 轻量,缓冲区可控 | 内部大量缓存,内存开销更大 |
8. JDK 原生 Timer vs ScheduledExecutorService 定时任务
表格
| 对比维度 | Timer | ScheduledExecutorService |
|---|---|---|
| 底层线程 | 单一线程串行执行所有任务 | 线程池多线程并发执行 |
| 任务阻塞影响 | 一个任务阻塞,所有任务延迟 | 任务间互不阻塞,独立执行 |
| 异常容错 | 任务抛异常,整个 Timer 直接终止 | 单任务失败不影响其他定时任务 |
| 延迟精度 | 时间漂移严重,误差大 | 调度精度更高,支持灵活延迟策略 |
9. 不可变集合 toUnmodifiableList () vs stream.toList () JDK16
表格
| 对比维度 | Collectors.toUnmodifiableList() | stream.toList() JDK16+ |
|---|---|---|
| null 元素 | 禁止存入 null,抛 NPE | 禁止存入 null,抛 NPE |
| 底层实现 | 内部 ImmutableList | 私有不可变实现类 |
| JDK 版本 | JDK10 + 可用 | 仅 JDK16 及以上 |
| 重复调用性能 | 每次创建全新不可变对象 | 语法更简洁,泛型推断更友好 |
10. AtomicInteger vs synchronized int 自增计数
表格
| 对比维度 | AtomicInteger | synchronized 修饰 int 变量 |
|---|---|---|
| 底层原理 | CAS 无锁自旋乐观锁 | 操作系统互斥悲观锁 |
| 并发性能 | 低竞争场景性能极高 | 高竞争大量上下文切换,性能差 |
| 阻塞行为 | 无线程阻塞,仅自旋重试 | 竞争失败线程阻塞挂起 |
| 适用场景 | 简单单一变量自增、计数 | 复合多变量同步操作、复杂业务逻辑 |
11. 方法静态参数 static 传参 vs 实例方法传参
表格
| 对比维度 | 静态方法 static | 实例普通方法 |
|---|---|---|
| 依赖资源 | 仅能访问静态变量,无法使用实例字段 | 可直接访问所有实例成员 |
| 调用方式 | 类名。方法 (),无需 new 对象 | 必须实例化对象才能调用 |
| 并发问题 | 静态变量全局共享,极易并发错乱 | 每个实例独立变量,天然隔离 |
| 内存生命周期 | 类加载常驻内存,全局唯一 | 随实例对象 GC 销毁 |
12. Spring @Resource vs @Autowired 依赖注入
表格
| 对比维度 | @Autowired (Spring 注解) | @Resource (JSR-250 标准) |
|---|---|---|
| 匹配规则 | 默认按类型 byType 注入 | 优先 byName 名称匹配,再 byType |
| 多实例处理 | 配合 @Qualifier 指定名称 | name 属性直接指定 bean 名称 |
| 标准规范 | Spring 框架专属,非 Java 标准 | Java 官方规范,兼容其他容器 |
| 必填校验 | required=true 默认必须存在 | 找不到对应 bean 直接报错 |
13. StringBuilder append 拼接链式 vs 分段拼接
表格
| 对比维度 | 链式连续 append | 多次分段 append 中间存临时变量 |
|---|---|---|
| 内存开销 | 仅一个缓冲区,无临时字符串 | 分段无额外开销,性能几乎无差异 |
| 可读性 | 一行长链式,过长不易阅读 | 拆分多行,逻辑清晰便于调试 |
| 扩容逻辑 | 统一单次扩容判断 | 多次 append 触发多次扩容校验 |
| 推荐写法 | 简短拼接使用链式;超长文本拆分多行 append |
14. 全局静态 Map 缓存 vs ThreadLocal 缓存
表格
| 对比维度 | static 全局 Map | ThreadLocal |
|---|---|---|
| 数据隔离 | 多线程共享,并发读写不安全 | 线程数据完全隔离,无竞争 |
| 过期清理 | 无自动过期,易内存泄漏 | 线程池必须手动 remove 清理 |
| 存储内容 | 全局公共配置、全线程共享数据 | 单次请求线程私有临时数据 |
| 并发锁 | 读写必须加锁控制并发 | 无锁,天然线程安全 |
15. 递归分治 Stream vs 循环分批处理大数据
表格
| 对比维度 | Stream 递归处理 | 循环分片分批处理 |
|---|---|---|
| 栈溢出风险 | 数据量大递归深度过高 StackOverflow | 无递归,栈深度恒定安全 |
| 内存占用 | 流式惰性求值,临时对象多 | 分批处理及时释放,内存峰值低 |
| 代码简洁度 | 流式一行完成逻辑 | 循环模板代码量大,繁琐 |
| 线上稳定性 | 超大集合禁止递归流式 | 大数据分片循环为生产标准方案 |
16. equalsObjects 工具类 Objects.equals () vs 手动 == 判空再 equals
表格
| 对比维度 | Objects.equals(a,b) | 手动 if 判 null + equals |
|---|---|---|
| 空指针安全 | 内置 null 判断,任意 null 不报错 | 漏写 null 判断直接 NPE |
| 代码长度 | 一行极简,无冗余 if 判断 | 多行 if 分支,模板代码多 |
| 底层逻辑 | 先判断地址相等,再判空,最后 equals | 重复手写相同逻辑,易出错 |
| 适用场景 | 所有对象相等对比,生产统一规范 | 不推荐手写判断,可读性差 |
17. 数据库主键自增 ID vs UUID 作为主键
表格
| 对比维度 | 自增数字 ID | UUID 字符串主键 |
|---|---|---|
| 索引性能 | 数字主键索引紧凑,查询极快 | 字符串索引体积大,性能衰减 |
| 分片分库 | 分库分表会出现 ID 冲突 | 全局唯一,多库无冲突问题 |
| 存储空间 | long 仅 8 字节 | UUID 占用 36 字符,空间消耗高 |
| 排序能力 | 天然按插入顺序排序 | 无序,无法根据主键排序数据 |
18. CompletableFuture exceptionally() vs whenComplete()
表格
| 对比维度 | exceptionally() | whenComplete() |
|---|---|---|
| 执行时机 | 仅任务异常时执行 | 正常 / 异常两种情况都会执行 |
| 返回值 | 可返回兜底默认结果 | 无返回值,仅做日志、资源清理 |
| 异常处理 | 捕获异常并提供默认返回 | 仅接收异常信息,无法修复结果 |
| 典型用途 | 异常兜底返回默认数据 | 统一打印成功 / 失败日志 |
19. 无界阻塞队列 LinkedBlockingQueue vs 有界 ArrayBlockingQueue
表格
| 对比维度 | 无界 LinkedBlockingQueue | 有界 ArrayBlockingQueue |
|---|---|---|
| 容量上限 | 无固定上限,无限添加元素 | 固定容量,满队列阻塞生产者 |
| OOM 风险 | 大量任务堆积直接内存溢出 | 容量限制,可控内存峰值 |
| 锁分离 | 读写双锁,并发吞吐量更高 | 单锁,读写互斥,并发性能低 |
| 生产规范 | 定时任务禁止无界队列 | 业务线程池强制使用有界队列 |
20. Java 原生序列化 Serializable vs JSON 序列化
表格
| 对比维度 | Serializable 二进制序列化 | JSON 序列化 (Jackson/Fastjson) |
|---|---|---|
| 跨语言 | 仅 Java 语言可用,跨语言无法解析 | 通用文本格式,支持所有语言 |
| 版本兼容 | 字段增减极易反序列化失败 | 兼容字段新增删除,容错性强 |
| 体积大小 | 二进制体积更小,传输快 | 文本体积更大,带宽消耗高 |
| 安全风险 | 反序列化漏洞高危风险 | 无原生反序列化漏洞,风险更低 |
21. 接口默认 default 方法 vs 抽象类公共实现方法
表格
| 对比维度 | 接口 default 默认方法 | 抽象类普通公共方法 |
|---|---|---|
| 多实现冲突 | 多接口同名 default 必须子类重写 | 单继承无方法冲突问题 |
| 成员变量 | 无法访问实例变量,仅常量 | 可直接使用子类实例字段 |
| 构造逻辑 | 无构造方法,不能初始化状态 | 拥有构造方法,可初始化公共属性 |
| 设计定位 | 扩展接口兼容新版本 | 抽取子类公共状态与逻辑 |
22. 单线程读取大文件逐行 vs 一次性加载全部到内存 List
表格
| 对比维度 | BufferedReader 逐行读取 | 一次性读取全部存入 List |
|---|---|---|
| 内存占用 | 仅单行驻留内存,无 OOM 风险 | 全量数据加载,大文件堆瞬间爆满 |
| 处理速度 | IO 频繁切换,略慢 | 一次加载完成,内存处理速度快 |
| 适用文件 | GB 级超大日志、数据文件 | KB/MB 级小文件,总量可控 |
23. JVM SerialGC vs ParallelGC
表格
| 对比维度 | Serial 串行收集器 | Parallel 并行收集器 |
|---|---|---|
| 工作线程 | 单线程执行所有 GC 动作 | 多线程并行 GC,充分利用多核 CPU |
| STW 停顿 | 单线程,停顿时间长 | 多核并行,大幅缩短停顿时长 |
| 适用机器 | 客户端、单核低配置程序 | 服务端多核服务器,线上默认老收集器 |
| 吞吐量 | 低,GC 占用大量 CPU 时间 | 高,提升程序整体吞吐量 |
24. 包装类缓存 Integer.valueOf () vs new Integer ()
表格
| 对比维度 | Integer.valueOf(num) | new Integer(num) |
|---|---|---|
| 缓存复用 | -128~127 复用缓存对象,减少堆创建 | 每次都新建全新堆对象,无复用 |
| 内存开销 | 高频数字复用,降低 GC 压力 | 大量重复数字生成大量对象 |
| 推荐规范 | 业务统一使用 valueOf,禁止 new Integer | 仅特殊隔离场景手动 new |
| == 对比 | 缓存区间内 == 相等,区间外 false | 任何数值两个 new 永远 ==false |
25. 前置判断短路 && vs 位与 &
表格
| 对比维度 | 短路逻辑 && | 位运算逻辑 & |
|---|---|---|
| 短路特性 | 左边 false,右侧表达式不执行 | 无论左侧真假,两边全部执行 |
| 使用场景 | 条件判断 if 分支 | 二进制位运算,掩码计算 |
| 性能差异 | 可跳过无意义判断,性能更优 | 两侧逻辑强制执行,存在无用计算 |
26. Spring 单例 Bean vs 多例 prototype Bean
表格
| 对比维度 | singleton 单例 (默认) | prototype 多例 |
|---|---|---|
| 实例数量 | 容器全局仅创建一个实例 | 每次获取创建全新对象 |
| 并发安全 | 实例共享,成员变量并发错乱 | 每次全新对象,无并发竞争 |
| 内存占用 | 常驻容器,长期占用堆 | 使用后无引用快速 GC 回收 |
| 适用场景 | 无状态工具类、Mapper、Service | 有状态、存储临时数据的 Bean |
27. File 老式文件 API vs Path NIO2 API
表格
| 对比维度 | java.io.File | java.nio.file.Path/Files |
|---|---|---|
| 操作能力 | 仅基础文件存在、删除、重命名 | 复制、移动、权限、遍历目录、逐行读取 |
| 异常机制 | 方法返回 true/false,失败无异常信息 | 抛出详细 IO 异常,便于定位问题 |
| 符号链接 | 无法识别软链接 | 原生支持符号链接处理 |
| 代码简洁度 | 大量冗余 try-catch,繁琐 | 工具类 Files 一行完成复杂操作 |
28. Stream sorted () 有状态操作 vs filter 无状态操作
表格
| 对比维度 | sorted/distinct 有状态操作 | filter/map 无状态操作 |
|---|---|---|
| 并行流性能 | 并行需要合并分片数据,开销巨大 | 分片独立处理,并行效率极高 |
| 内存占用 | 缓存全部元素完成排序,临时内存高 | 逐个处理,无需缓存元素 |
| 底层逻辑 | 必须收集全部元素再处理 | 来一个处理一个,惰性无缓存 |
| 并行优化 | 大数据并行排序收益极低 | 纯计算并行大幅提速 |
29. 方法传参传递集合副本 vs 传递原集合引用
表格
| 对比维度 | 传入集合拷贝副本 | 直接传入原集合引用 |
|---|---|---|
| 外部影响 | 外部修改原集合,方法内不受影响 | 外部增删元素同步影响方法内逻辑 |
| 内存开销 | 拷贝产生新集合,双倍内存占用 | 仅传递引用,无额外内存开销 |
| 数据安全 | 隔离外部数据,无并发修改异常 | 外部线程并发修改会抛出异常 |
| 适用场景 | 公共工具方法,防止外部篡改数据 | 内部私有调用,数据不会外部修改 |
30. try-with-resources 单资源 vs 多资源声明
表格
| 对比维度 | 单资源 try-with-resources | 多资源逗号分隔声明 |
|---|---|---|
| 关闭顺序 | 资源执行完毕自动关闭 | 声明逆序自动依次关闭所有资源 |
| 代码简洁度 | 简洁直观 | 一行声明多个流,无需多层嵌套 |
| 异常抑制 | 仅单一关闭异常 | 多个资源关闭异常全部保存为抑制异常 |
| 适用场景 | 单一文件 / 连接流 | 同时读写输入输出流、多连接同时释放 |
1万+

被折叠的 条评论
为什么被折叠?



