Java逻辑运算符短路

Java logical operator short-circuiting

哪一个集合是短路的,而复杂的条件表达式是短路的确切意思是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
  int x, y, z;

  x = 10;
  y = 20;
  z = 30;

  // T T
  // T F
  // F T
  // F F

  //SET A
  boolean a = (x < z) && (x == x);
  boolean b = (x < z) && (x == z);
  boolean c = (x == z) && (x < z);
  boolean d = (x == z) && (x > z);
  //SET B    
  boolean aa = (x < z) & (x == x);
  boolean bb = (x < z) & (x == z);
  boolean cc = (x == z) & (x < z);
  boolean dd = (x == z) & (x > z);

}


&&||操作员"短路",这意味着如果不需要,他们不会评估右侧。

当用作逻辑运算符时,&|运算符始终对两边进行评估。

每个操作员只有一种短路情况,它们是:

  • false && ...—不需要知道右手边是什么,结果必须是false
  • true || ...—不需要知道右手边是什么,结果必须是true

让我们在一个简单的例子中比较一下行为:

1
2
3
4
5
6
7
public boolean longerThan(String input, int length) {
    return input != null && input.length() > length;
}

public boolean longerThan(String input, int length) {
    return input != null & input.length() > length;
}

第二个版本使用非短路运算符&,如果inputnull则抛出NullPointerException,但第一个版本不例外地返回false


集合A使用短路布尔运算符。

"短路"在布尔运算符上下文中的含义是,对于一组布尔值b1、b2、…、bn,一旦这些布尔值中的第一个为真()或假(&;&;)时,短路版本将立即停止计算。

例如:

1
2
3
4
5
6
7
// 2 == 2 will never get evaluated because it is already clear from evaluating
// 1 != 1 that the result will be false.
(1 != 1) && (2 == 2)

// 2 != 2 will never get evaluated because it is already clear from evaluating
// 1 == 1 that the result will be true.
(1 == 1) || (2 != 2)


短路意味着如果第一个运算符决定最终结果,则不会检查第二个运算符。

例如,表达式为:真假

在的情况下,我们只需要其中一个方面是正确的。因此,如果左手边是真的,那么检查右手边就没有意义了,因此这一点也不会被检查。

同样,错误和正确

在这种情况下,我们需要双方都是真实的。因此,如果左手边是错误的,那么检查右手边就没有意义了,答案必须是错误的。因此,这将不会被检查。


1
boolean a = (x < z) && (x == x);

这类会短路,即如果(x < z)的评估结果为假,则不评估后者,a将为假,否则&&也将评估(x == x)

&是一个位运算符,也是一个不短路的布尔和运算符。

您可以通过以下方法对它们进行测试(查看在每种情况下调用该方法的次数):

1
2
3
4
5
6
7
8
9
10
public static boolean getFalse() {
    System.out.println("Method");
    return false;
}

public static void main(String[] args) {
    if(getFalse() && getFalse()) { }        
    System.out.println("=============================");        
    if(getFalse() & getFalse()) { }
}


简而言之,短路意味着一旦你知道答案不再改变,就停止评估。例如,如果您正在评估逻辑AND的链,并且在该链的中间发现了一个false,那么无论链中其余表达式的值是什么,您都知道结果将是错误的。一系列的OR也是如此:一旦你发现了true,你马上就知道答案了,因此你可以跳过对其余表达式的评估。

通过使用EDCOX1,0,而不是EDCOX1,2,EDCX1,1,而不是EDCOX1,3,则指示Java需要短路。你发帖的第一组是短路。

注意,这不仅仅是为了节省几个CPU周期:在这样的表达式中

1
2
3
if (mystring != null && mystring.indexOf('+') > 0) {
    ...
}

短路意味着正确操作和崩溃之间的区别(在mystring为空的情况下)。


&&&运算符之间存在一些差异。同样的差异也适用于|||。要记住的最重要的一点是,&&是一个只适用于布尔操作数的逻辑运算符,而&是一个适用于整数类型和布尔值的位运算符。

通过逻辑运算,可以进行短路,因为在某些情况下(如EDOCX1的第一个操作数〔1〕是false或EDOCX1的第一个操作数〔0〕是true时),不需要计算表达式的其余部分。这对于在访问一个文件或方法之前检查null以及在除以它们之前检查潜在的零非常有用。对于复杂表达式,表达式的每个部分都以相同的方式进行递归计算。例如,在以下情况下:

1
(7 == 8) || ((1 == 3) && (4 == 4))

只评估强调部分。要计算||,首先检查7 == 8是否为true。如果是的话,右手边就会完全被跳过。右侧仅检查1 == 3是否为false。因为它是,所以不需要检查4 == 4,整个表达式的计算结果是false。如果左手边是true,例如7 == 7,而不是7 == 8,整个右手边将被跳过,因为整个||的表达将是true,不管怎样。

对于逐位运算,您需要计算所有操作数,因为您实际上只是在组合这些位。布尔值实际上是Java中的一位整数(不管内部机制是如何工作的),在这种特殊情况下,你可以为位运算符做短路。不能短路一般整数&|运算的原因是,在任一操作数中,某些位可能是开的,而某些位可能是关的。像1 & 2这样的函数会得到零,但是如果不计算两个操作数,就无法知道这一点。


逻辑或:-如果至少有一个操作数的计算结果为true,则返回true。两个操作数在应用或运算符之前都要进行计算。

短路或:-如果左侧操作数返回真,则返回真而不计算右侧操作数。


Java提供了两种在大多数其他计算机语言中没有发现的有趣的布尔运算。这些和和或的辅助版本称为短路逻辑运算符。从上表中可以看到,当a为真时,无论b是什么,or运算符都会产生true。

同样,当a为false时,与运算符会导致false,无论b是什么。如果使用EDCOX1、0、EDCX1、1种形式,而不是EDCOX1、2、EDCX1和3种形式的这些运算符,Java就不会费心单独评估右操作数。当右操作数依赖于左操作数为真或假以正常工作时,这非常有用。

例如,下面的代码片段显示了如何利用短路逻辑评估,以确保在评估除法运算之前除法运算是有效的:

1
if ( denom != 0 && num / denom >10)

由于使用了and(&&的短路形式,因此不存在因除以零而导致运行时异常的风险。如果这一行代码是使用和的单个&版本编写的,则必须对双方进行评估,从而在denom为零时导致运行时异常。

在涉及布尔逻辑的情况下,使用AND和OR的短路形式是标准实践,而将单字符版本只用于位操作。但是,这个规则也有例外。例如,考虑以下语句:

1
 if ( c==1 & e++ < 100 ) d = 100;

这里,使用单个&确保增量操作将应用于e,无论c是否等于1。


1
if(demon!=0&& num/demon>10)

由于使用了和(&;&;)的短路形式,因此当DEMON为零时,不存在导致运行时异常的风险。

Herbert Schildt JAVA 2版第五版