Java开发笔记(十五)短路逻辑运算的优势

时间:2024-08-12 10:35:20

前面提到逻辑运算只能操作布尔变量,这其实是不严谨的,因为经过Java编程实现,会发现“&”、“|”、“^”这几个逻辑符号竟然可以对数字进行运算。譬如下面的代码就直接对数字分别开展了“与”、“或”、“异或”运算:

		// 3的二进制为00000011,7的二进制为00000111
int andNumber = 3&7; // 对两个数字进行“按位与”运算
System.out.println("andNumber="+andNumber);
int orNumber = 3|7; // 对两个数字进行“按位或”运算
System.out.println("orNumber="+orNumber);
int xorNumber = 3^7; // 对两个数字进行“按位异或”运算
System.out.println("xorNumber="+xorNumber);

上述代码也能成功编译运行,运行结果如下所示:

andNumber=3
orNumber=7
xorNumber=4

究其原因,这三个逻辑符号原是按位逻辑运算。所谓按位逻辑,指的是先将操作数转成二进制,再对二进制的操作数逐位进行逻辑运算,最后把每位的逻辑结果重新拼成一个二进制的运算值。例如数字3的二进制表达为00000011,数字7的二进制表达为00000111,那么对这两个二进制数进行“按位与”运算,得到的二进制结果为00000011即数字3;同样对这两个二进制数进行“按位或”运算,得到的二进制结果为00000111即数字7;继续对这两个二进制数进行“按位异或”运算,得到的二进制结果为00000100即数字4。
以上的实验结果,说明了逻辑与、或、异或符号实质是按位逻辑运算,之前的布尔变量只是按位逻辑的一种运算类型。既然按位逻辑比较的是左右两边的各个二进制位,就意味着必须先确定左右两边的操作数值,然后才能对两个操作数进行按位运算。这么看来,按位逻辑并非真正意义上的逻辑操作,正常情况的逻辑运算应当具备下列特征:
1、只判断真和假,不判断0和1,更不是什么逐位判断;
2、对于“与”运算,一旦左边的操作数为假,则不管右边为何,运算结果一定为假;
3、对于“或”运算,一旦左边的操作数为真,则不管右边为何,运算结果一定为真;
对比发现,按位逻辑不但不符合上述的第一点特征,也不符合第二点和第三点特征,因为按位逻辑需要左右两边都确定之后,才能墨守成规进行逻辑运算。显然这样做并不经济,倘若左边操作数就能确定运算结果,那又何苦画蛇添足进行右边的冗余计算?为解决按位逻辑存在的问题,Java引入了新的短路符号来帮忙,包括短路与符号“&&”和短路或符号“||”,短路的意思是:如果左边已经接通,那就不绕道右边了。
话虽如此,但又如何证明短路逻辑是否真的高效呢?下面通过一个例子来分辨按位逻辑和短路逻辑之间的区别,关键在于逻辑符号的右边需要修改变量值,为此引入了自增符号“++”。具体的逻辑运算代码如下所示,主要是比较逻辑与“&”和短路与“&&”的运算结果:

		int i=1, j=1;
// 对于按位逻辑运算,需要等待左右两边都计算完毕,然后进行按位逻辑判断
boolean result1 = 3>4 & ++i<5;
System.out.println("result1="+result1);
System.out.println("i="+i);
// 对于短路逻辑运算,一旦左边的计算能够确定结果,就立即返回逻辑判断的值,此时不再进行右边的计算
boolean result2 = 3>4 && ++j<5;
System.out.println("result2="+result2);
System.out.println("j="+j);

运行以上示例代码,得到下述的运算日志:

result1=false
i=2
result2=false
j=1

可见两个逻辑式子的运算结果都为false,不同之处在于:“&”符号同时进行了左右两边的运算,所以i++执行之后i值变为2;而“&&”符号先进行左边运算,发现3>4为假,说明与运算肯定为假,此时整个式子直接返回假,不再执行右边的计算,于是j值仍然为1(j++未执行)。从该实验看到,短路逻辑运算名副其实,其效率高于按位逻辑运算,因而在实际开发过程中,更经常使用短路符号“&&”和“||”进行逻辑运算,很少使用单个的“&”和“|”。