运算符的作用
运算符是把值组合起来、计算出新值的符号。你其实早就在随手使用它们了:+ 表示相加,> 表示比较。Java 把它们分成几大类:算术、比较、逻辑、赋值,以及自增和三元运算符这样的特殊运算符。
大多数运算符接收两个值(符号前一个、符号后一个)并产生一个结果。关键在于知道结果是什么类型,以及它们按什么顺序计算,初学者往往就栽在这里。
算术运算符
五个算术运算符作用于数字:+、-、*、/ 和 %(取余)。
% 运算符求的是除法之后的余数:17 % 5 是 2,因为 17 里有三个 5,还剩 2。它是判断能否整除的日常工具,n % 2 == 0 就是检查“n 是不是偶数”的标准写法。
还要注意 + 身兼两职:两边都是数字时它做加法,但只要有一边是 String,它就拼接文本。
第一行从左往右计算:"Total: " + 3 已经是一个字符串,所以 4 被当作文本追加上去。想让数学运算先算,就用括号把它括起来。
整数除法的陷阱
这是最常见的意外。当 / 的两个操作数都是整数时,Java 执行整数除法并丢掉小数部分:它不会四舍五入,而是向零截断。
要得到带小数的结果,至少要让一个操作数是 double:要么写成带 .0 的形式,要么用 (double) 转换其中一边。写成 (double)(5 / 2) 没有用,因为在转换之前,整数除法 5 / 2 已经算完了;你必须转换操作数,而不是结果。
比较运算符
比较运算符提出一个“是或否”的问题,并返回一个 boolean。一共有六个:==、!=、<、>、<=、>=。
注意区分 =(赋值,“把这个值放到这里”)和 ==(比较,“这两个相等吗?”)。把它们弄混是一个经典 bug。
有一点要特别注意:== 比较的是对象的引用,而不是内容。比较字符串时请用 .equals()。
对 int 和 boolean 这样的基本类型用 ==,比较字符串这类对象的内容时,一律用 .equals()。
逻辑运算符
逻辑运算符组合布尔值:&&(与)、||(或)和 !(非)。像“年满 18 岁并且有票”这样的条件,就是用它们来表达的。
&& 和 || 会短路:一旦答案确定,Java 就停止计算。对于 &&,如果左边是 false,右边根本不会检查;对于 ||,如果左边是 true,右边就会被跳过。这不只是一种优化,你还可以借助它来保证安全:
if (text != null && text.length() > 0) { ... }
如果 text 是 null,左边就是 false,text.length() 永远不会被调用,从而避免 NullPointerException。把顺序反过来,程序就会崩溃。
赋值与自增
= 用于赋值,Java 还有把运算和赋值合在一起的复合赋值运算符:+=、-=、*=、/=、%=。++ / -- 则用于加一或减一。
++ 有两种形式:后缀(count++)先返回旧值再加一;前缀(++count)先加一再返回新值。只有在同一个表达式里使用结果时,两者才有区别:
当 ++ 单独占一行时,后缀和前缀没有任何区别,所以选读起来更清楚的那种,也不要把自增塞进更大的表达式里。
三元运算符
三元运算符 condition ? a : b 是一种能产生值的紧凑版 if/else:条件为 true 时结果是 a,否则是 b。
它最适合简短的二选一赋值。不要在三元运算符里再嵌套三元运算符,那样很快就会变得难以阅读,用普通的 if/else 更清楚。
优先级与括号
运算符按固定的顺序计算,和数学很像:*、/、% 的优先级高于 + 和 -,它们又高于比较运算符,比较运算符高于 &&,最后是 ||。
你不需要把整张优先级表背下来。当一个表达式混用了多类运算符,或者你需要停下来想一想计算顺序时,就加上括号:它不花任何代价,还能让下一个读代码的人一眼看出你的意图。
下一页:类型转换
这里的好几个陷阱,比如整数除法、混用 int 和 double,归根结底都和类型有关。有意地在数字类型之间转换叫作强制类型转换,这就是下一页的内容。
常见问题
Java 中的 % 运算符是做什么的?
% 是取余(取模)运算符,它给出整数除法之后剩下的余数。7 % 3 是 1,10 % 2 是 0。它是判断能否整除的标准做法(n % 2 == 0 表示 n 是偶数),也常用来把一个值限定在某个范围内循环。
Java 中 5 / 2 为什么等于 2 而不是 2.5?
当两个操作数都是整数时,/ 执行整数除法并丢掉小数部分,所以 5 / 2 是 2 而不是 2.5。要得到 2.5,至少要有一个操作数是 double:写成 5.0 / 2、5 / 2.0,或者用 (double) 5 / 2 转换其中一边。
Java 中 == 和 equals() 有什么区别?
== 按值比较基本类型,但对于对象(包括 String),它比较的是引用,也就是它们是不是内存中的同一个对象。要比较对象的内容,请用 .equals()。用 == 比较两个字符串,即使文本相同也可能返回 false,所以比较字符串时始终用 "a".equals(b)。