Flask接口签名sign原理与实例代码浅析
466
2022-11-07
Java中短路运算符与逻辑运算符示例详解
1、逻辑运算符(部分)
符号
名称
&&
短路与运算符
||
短路或运算符
&
与运算符
|
或运算符
对于理工科学习者来说,逻辑运算是较为基础的概念,通常会在大一的离散数学课程中有所了解。在java以及更多C-Like语言中,&和|会分别表示逻辑运算中的与、或,他们的运算结果与我们在数学书中所学的逻辑运算规则并无差异。但是,在实际编程的过程中,我们反而会更多使用&&和||,甚至不少同学都不了解&、|两个运算符。那么,这究竟是为什么呢?
2、短路运算符
让我们来回到最初学习逻辑运算时解决问题的真值表,以“或运算”为例:
a
b
结果
true
true
true
true
false
true
false
true
true
false
false
false
a和b中,只要至少有一个为true,最终输出的结果则为true。那么,从算法优化的角度来思考问题的话,我们为了经过最少步骤还能输出可靠的结果,我们便可以把“或运算”定义为,有一个true,就输出true。
由此,“或运算”可以被优化为:从左向右,遇到有一个布尔表达式为true,则返回true,不进行之后的运算。
与之相似的,“与运算”可以被优化为:从左向右,遇到有一个布尔表达式为false,则返回false,不进行之后的运算。
故此,短路运算符被设计了出来。但为了兼顾“执行命令并返回”、“纯粹的数学计算”等多种应用场景,传统的非短路逻辑运算符也没有被短路逻辑运算符而取代。
此外,对于连写的短路运算符,如func1()||func2()||func3()||func4(),编译器也会为此优化,我们不妨来阅读这一部分的字节码来验证这个结论:
public static void main(String[] args) {
boolean b1 = func1() || func2() || func3() || func4();
System.out.println("------------------");
boolean b2 = func1() | func2() | func3() | func4();
}
// func1() - func4() here
短路“或”的字节码如下:
0: invokestatic #7 // Method func1:()Z
3: ifne 24
6: invokestatic #13 // Method func2:()Z
9: ifne 24
12: invokestatic #16 // Method func3:()Z
15: ifne 24
18: invokestatic #19 // Method func4:()Z
21: ifeq 28
24: iconst_1
25: goto 29
28: iconst_0
29: istore_1
3行、9行、15行的ifne是将栈顶元素与0(false)相比,如果不为false则跳转到24行将常量1(true)入栈,完成赋值,会跳过其余的执行。直到最后21行,才将最后方法结果的值再与0相比,如果还是0,则将常量0入栈,完成赋值。
普通“或”等字节码如下:
38: invokestatic #7 // Method func1:()Z
41: ihttp://nvokestatic #13 // Method func2:()Z
44: ior
45: invokestatic #16 // Method func3:()Z
48: ior
49: invokestatic #19 // Method func4:()Z
52: ior
53: istore_2
则是普通的或运算,无跳转,顺序执行最后赋值。
3、应用与陷阱
在最起初,笔者重新认识短路运算符是在这样一段代码中:
public LoginCheckDTO XxxLoginCheck(String password) {
//some codes
if ( password == null || password.length() == 0 ) {
return LoginCheckDTO.EMPTY_PASSWORD;
}
//some codes
}
当时笔者认为,如果password为null,在尝试调用password.length()时,会抛出空指针异常,故此写法不好。但在后来进行测试的时候,发现这样写并没有问题,查阅相关资料便了解了短路运算符的概念。
在这个例子中,当执行password == null返回true的时候,随后的表达式将不会被执行,就不存在抛出异常的情况了。这便是短路运算符较为常用的一个应用场景。
除此之外,我们还要警惕短路运算符导致的指令执行不完整。
譬如如下应用场景,我们希望利用条件语句来判断所有灯在上一状态是否都开着,并且无论如何我们希望最后打开所有的灯。但是我们错误使用了短路运算符:
public boolean checkAndTurnOnAll() {
return checkAndTurnOn1() && checkAndTurnOn2();
}
private boolean checkAndTurnOn1() {
boolean check = check1();
turnOn1();
return check;
}
private boolean checkAndTurnOn2() {
boolean check = check2();
turnOn2();
return check;
}
在这个场景中,如果第一盏灯在上vDAnbMwdbX一个状态是关闭状态,在checkAndTurnOn1()中虽然会执行turnOn1(),并且返回false,但由于短路特性checkAndTurnOn2()并不会被执行,所以最后期望的看到所有的灯都被打开不一定会实现。这种情况应当使用&。
总结
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~