加减乘除
+
-
*
/
很好理解。
除法里面,整型除以 0 ,会抛异常,合情合理。
浮点数除以 0,就有点奇葩了:
正浮点数除以 0 ,结果为正无穷大;
负浮点数除以 0 ,结果为负无穷大;
浮点数 0 除以 0 ,结果为 NaN;
这些知道就好,保证不除 0 ,才是关键。
还有 %
表示取余数,有时候会用到。
例如:判断奇偶数。这种情况,建议“判偶不判奇”。
因为:1 % 2 = 1
是奇数,-1 % 2 = -1
,也是奇数。
不如 i % 2 == 0
判断条件简单,且不易出错。
自增和自减
看代码就很好理解了:
1 | int c = 1; |
即便如此,当我们看到这样的代码:
1 | i = c++ + ++c + c++; |
还是会忍不住想问候一下对方的。
并且,由于编译机制等因素的不同,同一个表达式,在不同的程序语言环境下运行,还可能会产生不一样的结果。
因此,如果你需要使用它,应尽可能独立使用,保持简单,易于理解。
关于这个运算符,还有一个老梗。
有人嘲讽
c++
,说这种语言的名字本身就存在着 bug。
因为只有对它改进后,我们才有可能使用它。
如果当初命名为++c
应该就不会出现这样的问题了 :-D
三元运算符
当我们需要使用 if-else
的时候,不妨先考虑一下它吧。
1 | public int bigger(int x, int y) { |
关系运算符
需要注意的是它的“短路”特性。
我们经常会利用这种特性来编写代码,例如:
1 | if(string != null && string.length() != 0){} |
这样就确保不会产生空指针异常。
位运算符
boolean
类型的位运算(&
和 |
)和关系运算(&&
和 ||
)的结果一致,但是运算过程并不相同,不会“短路”,而是会计算所有的值。
利用 ^
(异或操作)交换元素,现在已经不是什么新鲜事。
这种操作的可逆性还是挺有趣的,并且相对于加法交换,还不会有溢出的风险。
1 | int a = 0; |
使用 <<
和 >>
实现 2 的 n 次方相乘或相除操作,也不是什么特别高深的手段。
1 | int m = 2; |
如果结果溢出,或者不是整数,只会使问题更复杂一些。
因此,位运算符虽然高效,看起来取巧,但是总的来说,不直观,不好理解,易于出错,除非对运算性能要求很高,否则,尽量不要使用它们。
运算符的优先级
我只知道:乘除高于加减。其余的我都不记,因为我会使用 ()
。
结语
最后再强调一下,保证参与运算的数值类型一致,可以避免很多莫名其妙的错误。
因为,当我们使用两个数值进行二元操作的时候,即使我们自己不进行手动的类型转换,编译器也会自动地把两个操作数转换成一致的类型,再做运算。
举一个“简单的”小例子:1
2
3
4
5byte b = 1;
b = b + 1; // 编译出错,因为 1 是 int 类型,因此,会先把 b 也转换成 int 类型。
b = (byte) (b + 1); // OK
b += 1; // Ok ,因为 += 自带强制类型转换技能!!相当于:b = (byte) ((int)b + 1);
`