Java中&和&&的区别是什么?

219

我一直认为Java中的&&运算符用于验证其布尔操作数是否都为true,而&运算符用于对两个整数类型执行位运算。

最近我了解到&运算符也可以用于验证其布尔操作数是否都为true,唯一的区别在于即使左侧操作数为false,它也会检查右侧操作数。

Java中的&运算符是否在内部进行了重载?或者背后还有其他概念吗?


3
可能是重复的问题,与 为什么我们通常使用 `||` 而不是 `|`,它们有什么区别? 相似。 - Blake Yarbrough
Double会尽可能地执行快捷方式。 - Nicholas Hamilton
在官方的sun/oracle文档中没有找到这方面的信息 :( - AlikElzin-kilaka
"短路"是这里的关键术语。 - AlikElzin-kilaka
15个回答

362

& <-- 验证两个操作数
&& <-- 如果第一个操作数的结果为false,则停止计算,因为整个表达式的结果将为false。

(x != 0) & (1/x > 1) <-- 这意味着先计算 (x != 0) ,然后计算 (1/x > 1) ,最后计算 &。问题在于当x=0时,会抛出异常。

(x != 0) && (1/x > 1) <-- 这意味着先验证(x != 0),只有在这是true的情况下,才会计算(1/x > 1),所以如果x=0,则完全安全,并且如果(x != 0)评估为false,则整个表达式直接评估为false而无需计算(1/x > 1)

编辑:

exprA | exprB <-- 这意味着先计算 exprA,然后计算 exprB,最后计算 |

exprA || exprB <-- 这意味着先验证 exprA,只有在其结果为false的情况下,才会计算 exprB 并执行 ||


15
在 if 语句中加入 & 或 | 的原因是什么?它比 && 和 || 更慢,为什么我们还要检查第二个条件,如果我们已经可以得到答案?能否提供一个现实的例子?注:& 和 | 分别表示按位与和按位或运算符,在 if 语句中使用它们时,表示同时考虑两个条件的结果。而 && 和 || 表示逻辑与和逻辑或运算符,当第一个条件就可以决定整个表达式的值时,后面的条件不会被计算。 - Michu93
25
如果第二个条件是一个具有你总是需要的副作用的函数调用,那么这就是一个例子。由于通常应该避免副作用,因此只有在极少数情况下才需要它,而我目前想不到一个现实的例子。 - Heinzi
12
在实现安全相关代码,特别是加密方面时,使用这些运算符可以防止基于时间测量的侧信道攻击(对不同结果有不同执行时间)。有时,“恒定时间”比“更快”的比较更有价值。 - Petr Dvořák
6
@PetrDvořák的例子很棒。此外,我还见过类似实现用于身份验证/登录代码(包括Spring Security),其中对于无效用户名的代码执行时间应该与对于无效密码的代码执行时间相同(即,前者不应该捷径)。 - java-addict301

66

除了不是惰性求值器而对两个操作数进行求值,我认为按位运算符的主要特征是像以下示例中比较操作数的每个字节:

int a = 4;
int b = 7;
System.out.println(a & b); // prints 4
//meaning in an 32 bit system
// 00000000 00000000 00000000 00000100
// 00000000 00000000 00000000 00000111
// ===================================
// 00000000 00000000 00000000 00000100

5
这个问题涉及到逻辑布尔运算,而不是位运算。 - user207421
33
它有助于像我这样只阅读标题的谷歌用户。 - Ad Infinitum

37
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

谢谢Andreas的编辑,也许这个其他的问题也有帮助:https://dev59.com/22865IYBdhLWcg3wCqHI - Torres

15

这取决于参数的类型...

对于整数参数,单个和符号("&")是按位与运算符。双个和符号("&&")仅适用于两个布尔型参数。

对于布尔参数,单个和符号构成无条件的 "逻辑与" 运算符,而双个和符号("&&")是 "条件逻辑与" 运算符。也就是说,单个和符号始终会评估两个参数,而双个和符号只有在第一个参数为 true 时才会评估第二个参数。

对于所有其他参数类型和组合,应该出现编译时错误。


11

&& 是短路运算符,而 & 是逻辑与运算符。

试一下这个。

    String s = null;
    boolean b = false & s.isEmpty(); // NullPointerException
    boolean sb = false && s.isEmpty(); // sb is false

8

我认为我的答案可以更容易理解:

&&&之间有两个区别。

如果它们被用作逻辑与

&&&可以作为逻辑与,当&&&的左右表达式结果都为真时,整个操作的结果可以为真。

&&&作为逻辑与时,有一个区别:

当使用&&作为逻辑与时,如果左侧表达式的结果为假,则右侧表达式将不会执行。

以例子为例:

String str = null;

if(str!=null && !str.equals("")){  // the right expression will not execute
        
}

如果使用 &:
String str = null;

if(str!=null & !str.equals("")){  // the right expression will execute, and throw the NullPointerException 
        
}

另一个更多的例子:
int x = 0;
int y = 2;
if(x==0 & ++y>2){
    System.out.print(“y=”+y);  // print is: y=3
}

int x = 0;
int y = 2;
if(x==0 && ++y>2){
    System.out.print(“y=”+y);  // print is: y=2
}

& 可以用作位运算符

& 可以用作按位与(Bitwise AND)运算符,&& 不能。

按位与(&)运算符仅在其操作数的两个位都为1时才产生1。然而,如果两个位都为0或两个位不同,则此运算符产生0。更准确地说,按位与(&)运算符返回1,只有当两个位都为1时,它返回0,只要任何一个位为0,它就返回0。

来自维基页面:

http://www.roseindia.net/java/master-java/java-bitwise-and.shtml


对于您丰富的解释,我表示敬意 @aircraft - java dev
这在维基源上是不正确的。例如,对于00000010和00000010进行按位与运算并不会得到数字1,而是得到数字2。这可以转换为布尔值True,但是这个答案声称它产生了1,这是明显错误的。 - Andreas Lundgren

7

JLS(15.22.2)所述:

当&、^或|运算符的两个操作数均为布尔类型或Boolean类型时,按位运算符表达式的类型为布尔类型。在所有情况下,必要时操作数都将进行自动拆装箱转换(§5.1.8)。

对于&,如果两个操作数的值都为true,则结果值为true;否则,结果为false。

对于^,如果操作数的值不同,则结果值为true;否则,结果为false。

对于|,如果两个操作数的值都为false,则结果值为false;否则,结果为true。

"诀窍"在于&既是整数按位运算符,也是布尔逻辑运算符。因此,把它视为运算符重载的一个例子是合理的。


5

‘&&’ : 逻辑与运算符根据其参数的逻辑关系产生一个布尔值true或false。

例如:Condition1 && Condition2

如果Condition1是false,则 (Condition1 && Condition2) 将始终为 false,这就是为什么这个逻辑运算符也称为短路运算符,因为它不评估另一个条件。如果Condition1是false,则无需评估Condtiton2。

如果Condition1为true,则评估Condtion2,如果为true,则总体结果为true,否则为false。

‘&’ : 按位与运算符。如果输入位都为一,则在输出中产生一个一(1)。否则产生零(0)。

例如:

int a=12;// 12 的二进制表示为1100

int b=6;// 6 的二进制表示为0110

int c=(a&b); // (12&6) 的二进制表示为0100

c的值为4。

有关参考,请参阅http://techno-terminal.blogspot.in/2015/11/difference-between-operator-and-operator.html


3
除了 && 和 || 是短路运算符外,在混合使用这两种形式时,还要考虑运算符优先级。我认为并不是每个人都能立刻意识到 result1 和 result2 包含不同的值。
boolean a = true;
boolean b = false;
boolean c = false;

boolean result1 = a || b && c; //is true;  evaluated as a || (b && c)
boolean result2 = a  | b && c; //is false; evaluated as (a | b) && c

3

使用布尔值时,这两者之间没有输出差异。你可以交换 && 和 & 或 || 和 | ,它永远不会改变表达式的结果。

区别在于处理信息的背景。当你使用表达式 "(a != 0) & (b != 0)",其中 a = 0,b = 1 时,会发生以下情况:

left side: a != 0 --> false
right side: b 1= 0 --> true
left side and right side are both true? --> false
expression returns false

当你写下表达式(a != 0) && (b != 0)并且a=0,b=1时,会发生以下情况:

a != 0 -->false
expression returns false

少一些步骤,少一些处理,更好的编码体验,特别是在处理许多布尔表达式或复杂参数时。


2
如果操作数具有副作用,则它将改变表达式的整体结果。 - user207421

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