3 分钟阅读
Optional 的默认值:orElse 会先算好再传入
某个缓存命中时,默认数据的数据库查询仍然发生,可能是因为把查询写进了 orElse。方法参数在进入方法前就会被求值。
某个缓存命中时,默认数据的数据库查询仍然发生,可能是因为把查询写进了 orElse。方法参数在进入方法前就会被求值。
排行榜只按分数排序,同分用户的次序可能让人困惑。稳定排序能保留输入顺序,但输入顺序本身未必稳定,尤其是来自数据库时。
配置查询里 get 返回 null,可能代表没有键,也可能代表这个键明确存了 null。直接套默认值,容易混淆这两种状态。
把列表放进 HashSet 能去重,但再拿出来可能不是原来的顺序。若测试只使用几个连续数字,这个问题还可能被掩盖。
复制 List 后修改元素,原列表仍然变化,是浅复制中常见的惊讶。容器独立和元素独立,需要分开判断。
在增强 for 循环中直接调用 list.remove,常会触发 ConcurrentModificationException。名称里有 Concurrent,并不意味着一定发生了多线程。
在方法中给参数重新赋值,调用方的变量不会跟着改变;但通过参数修改 List 内容,调用方却能看到变化。这两种行为并不矛盾。
遍历数组时多写一个等号,就会在最后一步越界。分页、切片和批处理也有类似问题:区间的端点究竟包含在内,必须说清楚。
计算成功率时,把两个整数相除再赋给 double,可能得到 0.0。错误发生在除法表达式内部,改变接收变量的类型不能修复已经丢失的信息。
登录名来自请求参数,配置项来自文件,二者即使显示一样,也不应该用 == 判断内容。字符串池会让部分示例碰巧通过,反而掩盖问题。
从 ThreadPoolExecutor 的任务接收顺序入手,理解有界队列为什么是系统容量的一部分。
理解 hashCode、equals 和可变键之间的关系,避免把放进去的数据变成“查不到的条目”。