布尔运算符的区别:&vs &&和| vs ||


Answers:


134

这些是按位与和按位或运算符。

int a = 6; // 110
int b = 4; // 100

// Bitwise AND    

int c = a & b;
//   110
// & 100
// -----
//   100

// Bitwise OR

int d = a | b;
//   110
// | 100
// -----
//   110

System.out.println(c); // 4
System.out.println(d); // 6

感谢卡洛斯指出在Java语言规格(相应章节15.22.115.22.2关于基于其输入操作者的不同的行为)。

的确,当两个输入均为布尔值时,这些运算符被视为布尔逻辑运算符,并且其行为类似于Conditional-And(&&)和Conditional-Or(||)运算符,但它们不会短路,因此以下操作是安全的:

if((a != null) && (a.something == 3)){
}

这不是:

if((a != null) & (a.something == 3)){
}

“短路”表示操作员不必检查所有条件。在上面的示例中,&&仅在a不存在时检查第二个条件null(否则整个语句将返回false,并且无论如何都要检查以下条件),因此的语句a.something不会引发异常,或者被认为是“安全的” 。”

&操作者始终检查子句中的每个状态,所以在上述例子中,a.something也可以当被评估a事实上是一个null值,产生一个异常。


1
想澄清一下。&仅在两者均为1时才会返回1?那么101和001是001吗?对?
gideon 2010年

@giddy @Jonathon-我更新了我的价值观以更好地表明这种情况。
贾斯汀·尼斯纳

不完整:它们也是LOGICAL运算符(对于布尔值)。
user85421

1
@ Carlos-不。他们仍然是按位运算符。它们的行为与非短路逻辑运算符相同。它们是有区别的。
贾斯汀·涅斯纳

4
什么是非短路逻辑运算符?运算符&和| (由OP提出)是“整数按位运算符”(JLS 15.22.1) “布尔逻辑运算符”(JLS 15.22.2)。还是Java语言规范对此有误?
user85421

108

我认为您在谈论这两个运算符的逻辑含义,这里有一个表格恢复:

boolean a, b;

Operation     Meaning                       Note
---------     -------                       ----
   a && b     logical AND                    short-circuiting
   a || b     logical OR                     short-circuiting
   a &  b     boolean logical AND            not short-circuiting
   a |  b     boolean logical OR             not short-circuiting
   a ^  b     boolean logical exclusive OR
  !a          logical NOT

short-circuiting        (x != 0) && (1/x > 1)   SAFE
not short-circuiting    (x != 0) &  (1/x > 1)   NOT SAFE

短路评估,最小评估或麦卡锡评估(在约翰·麦卡锡之后)是某些编程语言中某些布尔运算符的语义,只有在第一个参数不足以确定其值时,才执行或评估第二个参数表达式:AND函数的第一个参数的计算结果为false时,总值必须为false;并且当OR函数的第一个参数的计算结果为true时,总值必须为true。

不安全意味着操作员总是检查子句中的每个条件,因此在上面的示例中,当x实际上为0值时可能会评估1 / x,从而引发异常。


1
@Torres-请通过解释“短路”和“安全”来扩展答案。难道“排他性”或“逻辑不”也“不短路”吗?为何将其称为“逻辑非”而不是“布尔逻辑非”?为什么“逻辑非”不与“逻辑与”和“逻辑或”分组?好的答案,但需要工作。
tfmontague

@tfmontague,我已经解释了短路的含义(通过编辑此答案)。等待我的编辑被“同行评审”。
塔斯利姆·奥塞尼

关于不短路的“不安全”是什么?它不应该比使用短路安全吗?顺便说一句:您并没有真正解释“短路”一词。这意味着在“不短路”时首先评估所有零件,然后应用布尔运算,而在短路时,当第一个表达式满足条件时,停止评估,例如(a || b)不会评估b,如果a为true,则无论b是什么,or运算符都将返回true。
SCI

26

我知道这里有很多答案,但是它们似乎都有些混乱。因此,在从Java oracle学习指南进行了一些研究之后,我提出了何时使用&&或&的三种不同方案。这三种情况是逻辑与按位与布尔与

逻辑AND: 逻辑AND(又称条件AND)使用&&运算符。这是短路的意思:如果左操作数为false,则不会计算右操作数。
例:

int x = 0;
if (false && (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); // "0"

在上面的示例中,打印到x控制台的值将为0,因为if语句中的第一个操作数为false,因此java无需计算(1 == ++ x),因此将不计算x。

按位与: 按位与使用运算符。它用于对值执行按位运算。通过查看二进制数ex的运算,可以更轻松地了解发生了什么:

int a = 5;     //                    5 in binary is 0101
int b = 12;    //                   12 in binary is 1100
int c = a & b; // bitwise & preformed on a and b is 0100 which is 4

如您在示例中看到的,当数字5和12的二进制表示形式对齐时,按位与执行将仅生成二进制数字,其中两个数字中的相同数字均为1。因此0101&1100 == 0100。十进制的5和12 == 4。

布尔AND: 现在,布尔AND运算符的行为与按位AND和逻辑AND相似且不同。我喜欢将其视为在两个布尔值(或位)之间执行按位与运算,因此它使用运算符。布尔值也可以是逻辑表达式的结果。

它返回true或false值,非常类似于逻辑AND,但与逻辑AND不同,它不会短路。原因是,要对其执行按位与运算,它必须知道左右操作数的值。这是前一个:

int x = 0;
if (false & (1 == ++x) {
    System.out.println("Inside of if");
}
System.out.println(x); //"1"

现在,当该if语句运行时,即使左操作数为false,表达式也会执行(1 == ++ x)。因此,为x打印的值将为1,因为它已递增。

这也适用于逻辑OR(||),按位OR(|)和布尔OR(|),希望这可以消除一些混淆。


to preform that bitwise AND, it must know the value of both left and right operands这对我来说听起来不对。要执行一个操作,BITWISE AND您不需要知道正确的操作数就能知道结果,如果左边的操作数是FALSE。你能解释一下什么是正确的,但是推理,你的状态似乎不那么,至少对我来说..
科瑞图加伊

7

运算符&&和|| 是短路的,这意味着如果左侧表达式的值足以确定结果,则它们将不会评估其右侧表达式。


7
-1告诉OP他已经知道什么,但没有回答他实际问的问题。
Alnitak

5

&和| 提供与&&和||相同的结果 操作员。不同之处在于,它们始终对表达式的两边都进行计算,其中&&和|| 停止评估第一个条件是否足以确定结果。


1
错误的…。因为&&||仅在第一个条件为真时才评估两个结果,而返回。
Buhake Sindi

1
??&&仅在表达式的右手侧已经计算为true时计算它的右手侧。否则,它将停止评估,因为第一个false隐式意味着结果不能为真。参见jguru.com/faq/view.jsp?EID=16530
Brian Scott 2010年

1
( 2 & 4 )评估为false,而( 2 && 4 )评估为true。同一结果到底有多精确?
Piskvor于

1
@Piskvor-不是Java语言! 2 & 4结果为整数,而不是布尔值(在这种情况下为零)。2 && 4不会编译,&&仅接受布尔值。Java不允许混合使用布尔值和整数:零不为零falsefalse不为零...
user85421

1
@BuhakeSindi错误。因为&&只有第一个操作数为,它才计算第二个操作数true
洛恩侯爵,

2

在Java中,单个运算符&,|,^,!取决于操作数。如果两个操作数均为整数,则将执行按位运算。如果两者均为布尔值,则执行“逻辑”操作。

如果两个操作数不匹配,则会引发编译时错误。

双重运算符&&,|| 行为与它们的单个对应项相似,但是两个操作数都必须是条件表达式,例如:

if((a <0)&&(b <0)){...}或类似地,if((a <0)||(b <0)){...}

来源:java编程语言第4版



1

知道总是在同一表达式中使用条件AND和条件OR之前,先评估按位AND和按位OR运算符可能是有用的。

if ( (1>2) && (2>1) | true) // false!

1
您是说操作员优先而不是评估顺序吗?我宁愿看不到实际代码中使用的优先级差异。为此,请使用括号而不是按位运算符。
John Dvorak

1

&&; || 是逻辑运算符。...短路

&; | 是布尔逻辑运算符。...非短路

转向表达式的执行差异。不管左手边的结果如何,按位运算符都会对双方进行求值。但是,在使用逻辑运算符评估表达式的情况下,右手表达式的评估取决于左手条件。

例如:

int i = 25;
int j = 25;
if(i++ < 0 && j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

这将打印i = 26;j = 25,因为第一个条件为假,所以无论右侧条件如何,结果都会为假,因此绕过了右手条件。(短路)

int i = 25;
int j = 25;
if(i++ < 0 & j++ > 0)
    System.out.println("OK");
System.out.printf("i = %d ; j = %d",i,j);

但是,这将打印出i = 26;j = 26,


0

如果对涉及布尔运算符的表达式求值,则两个操作数都将求值。然后&运算符应用于操作数。

计算涉及&&运算符的表达式时,将计算第一个操作数。如果第一个操作数的计算结果为false,则跳过第二个操作数的计算结果。

如果第一个操作数返回值true,则对第二个操作数求值。如果第二个操作数返回值为true,则&&运算符将应用于第一个和第二个操作数。

类似| 和||。


0

尽管基本区别是&主要用于按位运算longint或者byte可以将其用于某种掩码,但是即使使用它而不是逻辑,结果也可能有所不同&&

在某些情况下,差异更加明显:

  1. 计算某些表达式很耗时
  2. 仅当前一个为真时,才可以评估其中一个表达式
  3. 表达式有一些副作用(预期或非预期)

第一点很简单,它不会引起错误,但是会花费更多时间。如果在一个条件语句中有几项不同的检查,请将价格较低或更有可能失败的检查放在左边。

第二点,请参见以下示例:

if ((a != null) & (a.isEmpty()))

这失败了null,因为评估第二个表达式会产生一个NullPointerException。逻辑运算符&&是惰性的,如果左操作数为false,则无论右操作数是什么,结果都是false。

第三点的示例-假设我们有一个使用DB的应用程序,没有任何触发器或级联。在删除建筑物对象之前,我们必须将部门对象的建筑物更改为另一座建筑物。我们还假设操作状态以布尔值返回(true =成功)。然后:

if (departmentDao.update(department, newBuilding) & buildingDao.remove(building))

即使部门更新由于某种原因失败,这也会对两个表达式求值,从而执行建筑拆除。用&&,它可以按预期工作,并且在第一次失败后停止。

至于a || b,等同于!(!a && !b),如果a为true 则停止,无需更多说明。

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.