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

125

我知道 &&|| 的规则,但是 &| 是什么意思?请用示例解释一下。


请参考这篇很好的解释:https://dev59.com/S2w05IYBdhLWcg3wqzms - JavaGeek
11个回答

157

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

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

感谢 Carlos 指出了 Java 语言规范 (15.22.1, 15.22.2) 中关于操作符基于其输入的不同行为的适当部分。

实际上,当两个输入都是布尔值时,这些操作符被认为是布尔逻辑操作符,并且与条件与 (&&) 和条件或 (||) 操作符类似,除了它们不会短路,所以以下代码是安全的:

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

这不是:

if((a != null) & (a.something == 3)){
}
"短路"指运算符不一定检查所有条件。在上面的例子中,当a不为null时(否则整个语句将返回false,无论如何都不会检查后续条件),&&仅检查第二个条件,因此a.something语句不会引发异常,或被认为是“安全”的。而&运算符总是检查子句中的每个条件,因此在上述示例中,如果a实际上是null值,则可能会评估a.something并引发异常。

1
想要澄清一下... 如果两个位置都是1,那么只会返回1吗?所以101和001会变成001?对吗? - gideon
1
不完整:它们也是逻辑运算符(用于布尔值)。 - user85421
1
@Carlos- 不是的。它们仍然是位运算符。它们只是表现得像非短路逻辑运算符一样。这是有区别的。 - Justin Niessner
4
非短路逻辑运算符是什么?操作符&和|(由提问者提出)是“整数按位运算符”(JLS 15.22.1)“布尔逻辑运算符”(JLS 15.22.2)。那么,Java语言规范有错吗? - user85421
你可以进一步阐述“这是安全的”和“这是不安全的”,以进一步完善答案。最好使用方法调用(会产生“副作用”)而不是访问属性来展示后者可能是不安全的。 - Jaywalker
显示剩余3条评论

116

我想你在谈论这两个运算符的逻辑含义,这里是一个表格概述:

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

短路求值,最小计算或者麦卡锡计算(John McCarthy 命名),是一些编程语言中某些布尔运算符的语义,在该语义下,只有在第一个表达式不能确定整个表达式的值时,第二个表达式才会被执行。当 AND 函数的第一个参数为 false 时,整个表达式必须为 false;当 OR 函数的第一个参数为 true 时,整个表达式必须为 true。

非安全操作 意味着操作符总是检查子句中的每个条件,因此在上述示例中,如果 x 实际上为 0 值,则会评估 1/x 并引发异常。


1
@Torres - 请进一步解释“短路”和“安全”的含义。此外,“异或”和“逻辑非”也不是“短路”的吗?为什么称其为“逻辑非”,而不是“布尔逻辑非”?为什么“逻辑非”没有与“逻辑与”和“逻辑或”分组?回答不错,但还需改进。 - tim-montague
@tfmontague,我已经解释了什么是短路(通过编辑这个答案)。正在等待我的编辑被“同行评审”。 - Taslim Oseni
不短路的代码有什么“不安全”的地方吗?使用短路难道不比不短路更安全吗? 顺便说一下,“短路”这个术语并没有得到很好的解释。它的意思是在“不短路”的情况下,所有部分都会先被评估,然后布尔运算被应用;而在短路的情况下,当第一个表达式满足条件时,评估就会停止,例如 (a || b) 如果 a 为真,或运算将返回 true,无论 b 是什么,b 就不会被评估。 - SCI

32

我知道这里有很多答案,但它们似乎有点令人困惑。因此,在Java Oracle学习指南中进行了一些研究后,我总结出了使用&&或&的三种不同情况。 这三种情况是逻辑AND位AND布尔AND

逻辑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不会被计算。
位运算与:位运算与使用&运算符。它用于对值执行按位运算。通过在二进制数字上进行操作,更容易看出发生了什么,例如:
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。我喜欢将其视为在两个布尔值(或比特)之间执行按位 AND,因此它使用&运算符。布尔值也可以是逻辑表达式的结果。

它返回 true 或者 false 值,就像逻辑 AND 一样,但与逻辑 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,因为它已经被递增。

这也适用于逻辑或(||),按位或(|)和布尔或(|)。希望这能消除一些困惑。


执行按位与运算时,必须知道左右操作数的值。这听起来对我来说不太对。要执行“按位与”运算,您不需要知道右操作数就能确定左操作数为“FALSE”时的结果。您所解释的是正确的,但您陈述的推理对我来说似乎不太正确,至少在我的看法中是这样的。 - Koray Tugay

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

8
对于告诉问题提出者他已经知道的事情并没有回答他实际提出的问题,打负分。 - Alnitak

5

& 和 | 与 && 和 || 运算符提供相同的结果。不同之处在于,它们总是评估表达式的两侧,而 && 和 || 在确定结果时如果第一个条件足以,则停止评估。


1
错误... 对于 && 运算符,会同时计算两个条件,而 || 只有在第一个条件为真时才返回结果。 - Buhake Sindi
1
什么?如果左边的表达式已经评估为true,那么&&运算符只会评估右边的表达式。否则,它会停止评估,因为第一个false意味着结果不能为true。请参考http://www.jguru.com/faq/view.jsp?EID=16530。 - Brian Scott
1
(2&4)的结果为false,而(2 && 4)的结果为true。这两个结果如何完全相同? - Piskvor left the building
1
@Piskvor - 不是Java! 2&4 的结果是一个整数,而不是布尔值(在这种情况下为零)。 2 && 4 将无法编译,&& 只接受布尔值。 Java 不允许混合布尔值和整数:零不是 falsefalse 不是零... - user85421
@Brian Scott:如果你在回答中加上了KarlP所补充的针对布尔值,那么这将是一个非常好的答案。我仍然给它点赞以平衡不合理的踩。 - Sean Patrick Floyd
1
@BuhakeSindi 错了。对于 &&,只有在第一个操作数为 true 时才会评估第二个操作数。 - user207421

3
在Java中,单个运算符 &, |, ^, ! 取决于操作数。如果两个操作数都是整数,则执行位运算。如果两个操作数都是布尔值,则执行“逻辑”运算。
如果两个操作数不匹配,则会抛出编译时错误。
双重运算符 &&, || 的行为类似于它们的单一对应项,但两个操作数必须是条件表达式,例如:
if (( a < 0 ) && ( b < 0 )) { ... } 或类似地, if (( a < 0 ) || ( b < 0 )) { ... }
来源:java programming lang 4th ed

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。由于第一个条件为false,右侧条件被绕过,因为无论右侧条件如何,结果都是false。(短路)
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,

1

3
&|也是布尔类型的布尔运算符。 - user207421

1
也许了解按位与和按位或运算符在同一表达式中使用条件与和条件或运算符之前总是被计算可能会很有用。
if ( (1>2) && (2>1) | true) // false!

1
你是指运算符优先级而不是求值顺序吗?我宁愿不在实际代码中看到优先级差异的使用。为此,请使用括号而不是位运算符。 - John Dvorak

0

如果计算一个包含布尔&运算符的表达式,则会计算两个操作数。然后将&运算符应用于操作数。

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

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

|和||同理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接