Java逻辑运算符短路


100

哪一组短路,这到底意味着复杂的条件表达式短路了?

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);

}

Answers:


244

&&||运营商“短路”,这意味着如果没有必要,他们不评价的右侧。

&|运营商,如逻辑运算符时,始终评估两侧。

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

  • false && ...-不必知道右侧是什么,因为结果只能是false那里的值
  • true || ...-不必知道右侧是什么,因为结果只能是true那里的值

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

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;
}

第二个版本使用非短路运算符,&并且将抛出NullPointerExceptionif inputis null,但是第一个版本将false毫无例外地返回。


9
我只想稍微扩展一下这个答案。&=运算符是x = x&表达式的简写,因此不会短路。| =运算符也是如此。
Stormcloud

11
我想强调的一件事,和&是二进制运算符,而&&和|| 是条件(逻辑)运算符。| 和&不仅处理布尔值,而&&和|| 仅适用于布尔值。
神话

1
他们不仅不评估右侧的表达式,而且不执行代码以进行任何评估。这是理解是否会产生副作用的关键点。
mckenzm

@mckenzm评估和执行之间有什么区别?
克朗

@Kronen执行可能会导致超出评估的结果,并产生副作用,例如异常或延迟,我将为此示例付出任何代价。
mckenzm

9

SET A使用短路布尔运算符。

在布尔运算符的上下文中,“短路”的含义是,对于一组布尔值b1,b2,...,bn,只要这些布尔值中的第一个为真,短路版本就会停止评估。 )或错误(&&)。

例如:

// 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)

请指定这种情况&&||工作方式不同,将停止对返回true的第一个操作数的求值;)
fge 2012年

1
事实上,要真正完成后,所有的&&||&|评估从左到右。对于一组布尔值b1,b2,...,bn,当这些布尔值中的第一个为true(||)或false(&&)时,短路版本将停止评估。
ah

@fge:是的,您当然是对的。您的定义比我的定义更严格。我已经用您评论中的句子更新了我的答案。我希望你不要介意。
afrischke'1

不用担心,如果不共享知识,那么它就没有价值。
fge 2012年

4

短路意味着如果第一个操作员确定最终结果,则不会检查第二个操作员。

例如,表达式为:True || 假

在||的情况下,我们需要的只是True 的一面。因此,如果左手边为真,则检查右手边没有意义,因此根本不会进行检查。

同样,False && True

对于&&,我们需要双方都为真。因此,如果左侧为False,则检查右侧没有意义,答案必须为False。因此,将完全不会检查。


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

这种会短路,意味着如果(x < z)评估为假,则后者不评估,a为假,否则&&也会评估(x == x)

& 是按位运算符,也是不短路的布尔AND运算符。

您可以通过以下方式对其进行测试(请参阅每种情况下调用该方法的次数):

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()) { }
}

-1你的回答表明,&唯一位运算符,但事实并非如此。它也是一个布尔“或”运算符。
波希米亚

@波西米亚人:感谢大家的注意。true & false评估为假。您能解释一下这个“布尔”或“运算符”吗?可能是我听不到您要说的话。
Bhesh Gurung 2012年

对不起-我的意思是布尔值AND,不是OR!即true & false是有效的语法。-1删除了:)
波西米亚风格

4

在平原而言,短路手段停止评估,一旦你知道答案不能再更改。例如,如果您正在评估逻辑ANDs 的链,并且FALSE在该链的中间发现a ,则无论链中其余表达式的值是多少,您都知道结果将为假。对于ORs 链也是如此:一旦找到a TRUE,便立即知道答案,因此可以跳过对其余表达式的求值。

您可以使用&&代替&||来向Java表示要短路|。帖子中的第一组是短路。

请注意,这不仅仅是节省一些CPU周期的尝试:在这样的表达式中

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

短路是指正确操作和崩溃之间的区别(在mystring为null的情况下)。


2

Java提供了两个其他大多数计算机语言都找不到的有趣的布尔运算符。这些AND和OR的辅助版本称为短路逻辑运算符。从上表中可以看出,无论B是什么,OR运算符在A为true时都为true。

类似地,无论B是什么,当A为false时,AND运算符都会得出false。如果使用||&&形式,而不是这些运算符的|&形式,则Java不会费心地单独评估右手操作数。当右侧操作数依赖于左侧的true或false才能正常运行时,这非常有用。

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

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

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

在涉及布尔逻辑的情况下,通常使用AND和OR的短路形式,而将单字符版本专用于按位运算。但是,此规则也有例外。例如,考虑以下语句:

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

此处,使用单个&可确保将增量运算应用于e是否c等于1。


2

如果至少一个操作数的值为true,则逻辑OR:-返回true。在应用OR运算符之前,将对这两个操作数求值。

短路OR:-如果左侧操作数返回true,则返回true,而不评估右侧操作数。


2

&&&运算符之间有一些区别。|和均适用相同的区别||。要记住,最重要的是,&&是一个逻辑只适用于布尔操作数的运营商,同时&是一个按位适用于整数类型以及布尔运算符。

与逻辑操作,你可以做短路,因为在某些情况下(如的第一个操作数&&false,或第一个操作数||true),你不需要计算表达式的其余部分。这对于执行诸如null在访问文件或方法之前进行检查以及在将其除以之前检查可能的零之前的操作非常有用。对于复杂的表达式,将以相同的方式递归评估表达式的每个部分。例如,在以下情况下:

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

仅强调部分将被评估。要计算||,请首先检查是否7 == 8true。如果是这样,则将完全跳过右侧。右侧仅检查是否1 == 3false。既然如此,4 == 4则无需检查,整个表达式的计算结果为false。如果左侧是true,例如7 == 7而不是7 == 8,则整个右侧将被跳过,因为整个||表达式将是true无关紧要的。

使用按位运算,您需要评估所有操作数,因为您实际上只是在组合位。布尔实际上是Java中的一位整数(无论内部如何工作),在这种特殊情况下,您可以对按位运算符进行短路只是一个巧合。您不能使通用整数&|操作短路的原因是,任一操作数中的某些位可能会打开,而某些位可能会关闭。诸如此类的结果1 & 2为零,但是如果不对两个操作数求值,就无法知道这一点。


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

由于使用的是AND(&&)的短路形式,因此当monmon为零时,就不会导致运行时异常。

参考 Herbert Schildt撰写的Java 2 Fifth Edition

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.