【问题标题】:Differences in boolean operators: & vs && and | vs ||布尔运算符的区别:& vs && 和 |与 ||
【发布时间】:2011-04-30 04:42:16
【问题描述】:

我知道&&|| 的规则,但&| 是什么?请用一个例子给我解释一下。

【问题讨论】:

标签: java bitwise-operators logical-operators boolean-logic


【解决方案1】:

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

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.115.22.2)中关于运算符根据输入的不同行为的相应部分。

确实,当两个输入均为布尔值时,运算符被视为布尔逻辑运算符,其行为类似于条件与 (&&) 和条件或 (||) 运算符,除了它们不短路所以虽然以下是安全的:

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

这不是:

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

“短路”是指操作员不必检查所有条件。在上面的例子中,&& 只会在a 不是null 时检查第二个条件(否则整个语句将返回 false,并且无论如何检查以下条件都没有实际意义),所以@987654331 的语句@ 不会引发异常,或者被认为是“安全的”。

& 运算符始终检查子句中的每个条件,因此在上面的示例中,当 a 实际上是 null 值时,可能会评估 a.something,从而引发异常。

【讨论】:

  • 想要澄清.. & 只有当两者都是 1 时才会返回 1?那么 101 和 001 会是 001 吗?对吗?
  • @giddy @Jonathon - 我更新了我的价值观以更好地展示这种情况。
  • 不完整:它们也是逻辑运算符(用于布尔值)。
  • @Carlos- 不,它们仍然是位运算符。它们的行为与非短路逻辑运算符相同。有区别。
  • 什么是非短路逻辑运算符?运算符 & 和 | (由 OP 询问)是“整数位运算符”(JLS 15.22.1)“布尔逻辑运算符”(JLS 15.22.2)。还是 Java 语言规范对此有误?
【解决方案2】:

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

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

Short-circuit evaluation、最小评估或 McCarthy 评估(在 John McCarthy 之后)是某些编程语言中某些布尔运算符的语义,其中仅当第一个参数不足以确定值时才执行或评估第二个参数表达式的:当 AND 函数的第一个参数计算结果为 false 时,整体值必须为 false;当 OR 函数的第一个参数计算结果为 true 时,整体值必须为 true。

不安全 表示运算符总是检查子句中的每个条件,因此在上面的示例中,当 x 实际上是 0 值时,可能会计算 1/x,从而引发异常.

【讨论】:

  • @Torres - 请通过解释“短路”和“安全”来扩展您的答案。 “异或”和“逻辑非”也是“不短路”吗?为什么它被称为“逻辑非”而不是“布尔逻辑非”?为什么“逻辑非”不与“逻辑与”和“逻辑或”分组?很好的答案,但需要工作。
  • @tfmontague,我已经解释了短路的含义(通过编辑这个答案)。等待我的编辑被“同行评审”。
  • 什么是不短路的“不安全”?它不应该比使用短路更安全吗?顺便说一句:您并没有真正解释“短路”一词。这意味着在“不短路”时首先评估所有部分,然后应用布尔运算,而在短路时停止评估,当第一个表达式满足条件时,如 (a || b) 不会评估 b,如果 a 为真并且 or 操作将返回真,无论 b 是什么。
【解决方案3】:

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

逻辑与: 逻辑与(又名条件与)使用 && 运算符。它的短路含义:如果左操作数为假,则不会计算右操作数。
示例:

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 不会计算出来的。

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

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 不同,它没有短路。原因是它要执行按位与,它必须知道左右操作数的值。这是一个前任:

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

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

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

【讨论】:

  • to preform that bitwise AND, it must know the value of both left and right operands 这听起来不对。要执行BITWISE AND,如果左操作数是FALSE,您不需要知道右操作数就能计算出结果。您的解释是正确的,但至少在我看来,您所说的推理似乎并非如此......
【解决方案4】:

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

【讨论】:

  • -1 告诉 OP 他已经知道什么,而不是回答他实际提出的问题。
【解决方案5】:

& 和 |提供与 && 和 || 相同的结果运营商。不同之处在于它们总是计算表达式的两边,其中 && 和 ||停止评估第一个条件是否足以确定结果。

【讨论】:

  • 错误.... 对于&&,它会评估两种结果,而|| 仅在第一个条件为真时返回。
  • 嗯? && 仅在左侧已经计算为真时才计算表达式的右侧。否则它会停止评估,因为第一个错误暗示结果不能为真。见jguru.com/faq/view.jsp?EID=16530
  • ( 2 & 4 ) 计算结果为 false,而 ( 2 && 4 ) 计算结果为 true。这究竟是怎样的结果?
  • @Piskvor - 不是在 Java 中! 2 & 4 产生一个整数,而不是布尔值(在这种情况下为零)。 2 && 4 不会编译,&& 只接受布尔值。 Java 不允许混合布尔值和整数:零不是falsefalse 不是零...
  • @BuhakeSindi 错了。对于&&,如果第一个操作数是true,它只会计算第二个操作数。
【解决方案6】:

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

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

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

if (( a

来源:java 编程语言第 4 版

【讨论】:

    【解决方案7】:

    &| 是整数类型的按位运算符(例如 int):http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

    &&|| 仅对布尔值进行操作(和短路,正如其他答案已经说过的那样)。

    【讨论】:

    • &| 也是布尔类型的布尔运算符。
    【解决方案8】:

    知道按位 AND 和按位 OR 运算符总是在条件 AND 和条件 OR 用于同一个表达式之前进行计算可能会很有用。

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

    【讨论】:

    • 您是指操作员优先级而不是评估顺序吗?我宁愿看不到实际代码中使用的优先级差异。为此,请使用括号而不是按位运算符。
    【解决方案9】:

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

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

    转移到表达式的执行差异。位运算符评估两边,而不考虑左侧的结果。但是在使用逻辑运算符计算表达式的情况下,右手表达式的计算取决于左手条件。

    例如:

    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,

    【讨论】:

      【解决方案10】:

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

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

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

      类似 |和||。

      【讨论】:

        【解决方案11】:

        虽然基本区别在于&amp; 主要用于longintbyte 上的按位运算,但它可用于某种掩码,但即使您使用它,结果也会有所不同而不是逻辑&amp;&amp;

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

        1. 评估某些表达式非常耗时
        2. 只有当前一个表达式为真时,才能评估其中一个表达式
        3. 表达式有一些副作用(有意或无意)

        第一点很简单,它不会导致任何错误,但需要更多时间。如果您在一个条件语句中有多个不同的检查,请将成本较低或更有可能失败的检查放在左侧。

        关于第二点,请看这个例子:

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

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

        第三点的例子——假设我们有一个使用数据库的应用程序,没有任何触发器或级联。在我们移除一个建筑物对象之前,我们必须将一个部门对象的建筑物更改为另一个。假设操作状态作为布尔值返回(true = 成功)。那么:

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

        这会评估两个表达式,因此即使部门更新由于某种原因失败,也会执行建筑物移除。使用&amp;&amp;,它按预期工作,并在第一次失败后停止。

        至于a || b,相当于!(!a &amp;&amp; !b),如果a为真则停止,无需解释。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-20
          • 2011-09-11
          • 2011-09-27
          • 2011-03-27
          相关资源
          最近更新 更多