Java 项目里的那些坑
1)NullPointerException 不是最大的问题,“被吞掉的 NPE” 才是
现象:接口偶发返回默认值/空列表,日志无异常,但业务数据不对。
根因:在
catch (Exception e){}里吞异常,或Optional.orElseGet()里调用了含 NPE 的逻辑。规避:
严禁“裸 catch”;NPE 统一加业务语义并打点。
使用
Objects.requireNonNull在入口处早失败。
// 入口防御式校验 UserInput in = Objects.requireNonNull(req.getInput(), "input is required");
2)BigDecimal 的两大雷:构造方法和比较
现象:金额出现 0.3000000000004 或
equals比较失败。根因:
new BigDecimal(0.1)用了 double;equals比较精度和数值。规避:
用
BigDecimal.valueOf(double)或字符串构造。金额比较用
compareTo,显示用统一setScale。
BigDecimal a = BigDecimal.valueOf(0.1); BigDecimal b = new BigDecimal("0.2"); a.add(b).setScale(2, RoundingMode.DOWN); if (a.compareTo(b) == 0) { /* equal by value */ }
3)equals/hashCode + 可变字段 = 散列表噩梦
现象:元素“神秘”从
HashSet里消失,HashMap查不到值。根因:作为 key 的对象放进 Map 后,参与 hash 的字段被修改。常见于 Lombok
@Data默认把所有字段纳入equals/hashCode。规避:
key 对象设计成不可变(
final字段,去 setter)。Lombok 明确指定:
@EqualsAndHashCode(of = {"id"})。
@Value // Lombok 不可变对象 public class UserKey { Long id; }
4)自动装箱陷阱:== 比较 Integer
现象:
Integer比较在 [-128,127] 内“看似正确”,其他值就错。规避:一律用
Objects.equals(a, b),或先拆箱比较基本类型。
5)时区/时间:开发好好的,上线全乱了
现象:当天订单跑到前一天/后一日;定时任务错点。
根因:使用
LocalDateTime存库、机房/容器默认时区不同、MySQLtimestamp与datetime混用。规避:
服务统一使用 UTC 存储(数据库、MQ),展示再转换。
明确 JVM 启动参数:
-Duser.timezone=UTC。Java 端用
ZonedDateTime/Instant;MySQL 用timestamp并统一时区。
