程序第一次「长出脑子」是在这一章:根据条件走不同的路。if/else 和 switch 是所有语言共享的积木,但 Java 有几个值得专门讲的点:短路求值是工程武器而不只是考点、字符串比较的 == 陷阱(全 Java 最著名的初学者坑)、以及 JDK 14 之后的箭头 switch 为什么值得直接当主力用。这一章篇幅不大,但那两个坑的杀伤力是长尾的,值得慢读。
比较运算符(== != > <)产出 boolean,逻辑运算符组合它们:&& 与、|| 或、! 非。关键性质是短路:
// && 左边为 false,右边不执行;|| 左边为 true,右边不执行
if (arr != null && arr.length > 0) { ... } // 安全判空的标准写法
if (denom != 0 && a / denom > 2) { ... } // 先挡住除零
这不是「少算几步」的优化,是依赖顺序的正确性工具:右边依赖左边「活着」的前提(空指针检查、除零检查、越界检查),顺序写反程序就炸。顺便记住和它相对的 &、|(非短路版,两边都算),日常逻辑判断用短路版,位运算才是 & 的本职(第 5 章讲)。
三目运算符 条件 ? a : b 是 if/else 的表达式版,适合「给变量挑值」这种单行场景:
int max = a > b ? a : b; // 比 if-else 四行清爽
嵌套三目(a ? b : c ? d : e)请直接判死刑,没人想读懂它。
if (score >= 90) {
grade = 'A';
} else if (score >= 80) { // else if 是「else 里再套 if」的缩进糖
grade = 'B';
} else {
grade = 'C';
}
三条纪律,每条都有事故背书。永远写大括号,哪怕只有一句:Java 没有 Python 的缩进语义,if (x) doA(); doB(); 里 doB() 根本不在 if 里(悬挂语句),加上大括号这类事故消失。条件区间别写重叠:if (x > 80) 后再 if (x > 90),第二个永远进不去(90 的分支被 80 拦截),升序 if-else 要保证区间互斥,从大到小或从小到大一以贯之。else 配对看最近未匹配的 if(悬挂 else 问题),缩进会骗人,大括号不会。
先看事故现场:
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false!看着相等,比出来不等
System.out.println(a.equals(b)); // true,这才是比内容
原理一句话:Java 里 == 比的是引用(门牌号,计组课第 10 章的语言),equals 比的才是内容。a 和 b 是两个不同的 String 对象(两张门牌,里面住着一样的字),== 判 false。更迷惑的是有时 == 又「碰巧」true(字符串字面量常量池复用,第 9 章讲),这种「有时对有时错」的行为让它成为 Java 面试和事故清单的双料冠军。
工程纪律只有一条:比较字符串内容,永远用 equals:
if (input.equals("quit")) { ... } // 对
if ("quit".equals(input)) { ... } // 更稳的写法:字面量在前,input 为 null 也不炸
第二种写法(常量在前)是防 null 的技巧:null.equals 会抛 NullPointerException,反过来则安全返回 false。C 语言比字符串要手动 strcmp(第 6 章),Java 的 == 陷阱本质是「长得像值类型,实际是引用」的语言设计代价,这个伏笔到第 8 章(引用语义)正式收线。
传统 switch(和 C 同款语义):
switch (day) {
case 1:
case 2:
case 3:
name = "工作日";
break; // 忘了 break?贯穿(fall-through)到下一个 case!
default:
name = "休息日";
}
fall-through 是 C 遗产里的地雷:漏一个 break,逻辑静默串台。JDK 14 起的箭头语法直接判了 break 的死刑,而且 switch 升级成了表达式:
String name = switch (day) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "休息日";
default -> "未知";
}; // 箭头分支无贯穿、必须穷尽(编译器强制 default 或覆盖全部可能)
新代码一律用箭头版:无贯穿、可当表达式、编译器帮查漏,老代码的三宗罪一次清零。JDK 21 再进一步支持模式匹配(case Integer i -> ...),那是后话。
if (x = 1) 经典 bug,在 Java 里对 int 直接编译错误(boolean 类型独立),但 boolean 变量 if (flag = true) 依然合法,警惕。a = "hi"; b = "hi")和 new String 构造,打印 a == b 与 a.equals(b) 的四种组合结果,并猜想字面量那次 == 为 true 的原因(常量池,先猜,第 9 章对答案)。int[] a = null; if (a != null && a.length > 0) 和把条件顺序反过来的版本各会发生什么?写出原因。