德摩根定律是提升代码可读性与健壮性的实用工具,核心为:!(a && b) ⇔ !a || !b,!(a || b) ⇔ !a && !b;需结合真值表验证、语义命名和空安全设计落地。

德摩根定律不是用来“炫技”的数学工具,而是帮你把绕口令式的条件写成能一眼看懂的业务逻辑。核心就两条:!(A && B)等价于 !A || !B,!(A || B)等价于 !A && !B。用对了,代码可读性、健壮性和测试覆盖率都会明显提升。
识别该出手的嵌套否定场景
以下几种写法,大概率藏着可简化的德摩根机会:
-
if (!isValid || !isReady)→ 实际想表达“只要一个不满足就跳过”,应改为if (!(isValid && isReady)) -
if (obj == null || !obj.isActive())→ 安全但语义弱,换成if (!Objects.nonNull(obj) || !obj.isActive())不更啰嗦,反而暴露意图;更好的是提取为if (!isActivated(obj)) -
if (!a && !b && !c)→ 检查“全部无效”,其实等价于if (!(a || b || c)),后者更贴近“只要有一个有效就通过”的业务表述
用真值表验证再改,别靠脑算
人脑对多层否定+或运算极易出错。比如原始表达式是 !((A && B) || C),别急着展开,先列个三变量真值表(共8行),确认你想要的输出和化简后是否一致。验证通过再动代码,避免引入隐藏 bug。
常见错误:把 !(A && B) 错当成 !A && !B,漏掉“或”的本质;或者在含 null 的对象链中,错误调整判断顺序导致 NPE。
配合语义命名,让简化落地
德摩根只是第一步,关键要让简化后的逻辑“活”在代码里:
- 把
!(user != null && user.hasRole("admin"))改成!isAdministrator(user),方法体内用Objects.nonNull(user) && user.hasRole("admin") - Stream 过滤不用
u -> !u.isActive(),而定义Predicate<user> isActive = User::isActive;</user>,再用list.stream().filter(isActive.negate()).collect(...) - 守卫条件统一前置:把多个
if (x != null && x.isValid()) {...}提炼为if (!isValidContext(x)) continue;,内部实现用德摩根组织条件
警惕短路与空安全的耦合陷阱
Java 的 && 和 || 是短路的,但加了 ! 后,人脑容易忽略执行顺序。例如:
-
if (obj != null && !obj.isActive())安全,因为!= null在前 - 若写成
if (!obj.isActive() && obj != null),一旦obj为 null 就直接 NPE - 德摩根改写后(如
!(obj == null || !obj.isActive()))天然要求左侧先判空,倒逼你写出更安全的结构
这时候顺手换成 Objects.nonNull(obj) && obj.isActive(),既清晰又利于静态分析工具识别。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











