我只是想知道为什么我们通常在两个布尔值之间使用逻辑OR ||,而不是按位或|,尽管它们都工作得很好。

我的意思是,看看下面这些:

if(true  | true)  // pass
if(true  | false) // pass
if(false | true)  // pass
if(false | false) // no pass
if(true  || true)  // pass
if(true  || false) // pass
if(false || true)  // pass
if(false || false) // no pass

我们可以用|代替||吗?&和&&也是一样。


当前回答

|是位操作符。||是逻辑运算符。

一个会取两个比特或者它们。

一个人将决定真理(这个或那个)如果这个是真的或那个是真的,那么答案就是真的。

哦,该死的人回答这些问题很快。

其他回答

有很多用例表明为什么你应该选择||而不是|。有些用例必须使用|操作符来检查所有条件。

例如,如果您希望检查表单验证,并且希望向用户显示所有带有错误文本的无效字段,而不仅仅是第一个无效字段。

||算子是,

   if(checkIfEmpty(nameField) || checkIfEmpty(phoneField) || checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

   private boolean checkIfEmpty(Widget field) {
      if(field.isEmpty()) {
        field.setErrorMessage("Should not be empty!");
        return true;
      }
      return false;
   }

因此,在上面的代码片段中,如果用户提交的表单中所有字段都是空的,那么只有nameField将显示错误消息。但是,如果你把它改成,

   if(checkIfEmpty(nameField) | checkIfEmpty(phoneField) | checkIfEmpty(emailField)) {
      // invalid form with one or more empty fields
   }

无论真实情况如何,它都会在每个字段上显示正确的错误信息。

Java运营商

|是位或,||是逻辑或。

||是逻辑或,|是位或。

其他答案很好地涵盖了运算符之间的函数差异,但这些答案可以适用于目前存在的几乎每一种c派生语言。这个问题带有java的标签,因此我将努力具体地、从技术上回答java语言。

&和|可以是整数位运算符,也可以是布尔逻辑运算符。按位运算符和逻辑运算符(§15.22)的语法是:

AndExpression:
  EqualityExpression 
  AndExpression & EqualityExpression

ExclusiveOrExpression:
  AndExpression 
  ExclusiveOrExpression ^ AndExpression

InclusiveOrExpression:
  ExclusiveOrExpression 
  InclusiveOrExpression | ExclusiveOrExpression

The syntax for EqualityExpression is defined in §15.21, which requires RelationalExpression defined in §15.20, which in turn requires ShiftExpression and ReferenceType defined in §15.19 and §4.3, respectively. ShiftExpression requires AdditiveExpression defined in §15.18, which continues to drill down, defining the basic arithmetic, unary operators, etc. ReferenceType drills down into all the various ways to represent a type. (While ReferenceType does not include the primitive types, the definition of primitive types is ultimately required, as they may be the dimension type for an array, which is a ReferenceType.)

位运算符和逻辑运算符具有以下属性:

这些运算符具有不同的优先级,&具有最高优先级,|具有最低优先级。 这些操作符在语法上都是左关联的(每个组从左到右)。 如果操作数表达式没有副作用,每个操作符都是可交换的。 每个运算符都是结合的。 位运算符和逻辑运算符可用于比较数值类型的两个操作数或布尔类型的两个操作数。所有其他情况都会导致编译时错误。

操作符是位操作符还是逻辑操作符的区别取决于操作数是“可转换为基本整型”(§4.2)还是boolean或boolean类型(§5.1.8)。

如果操作数是整型,则对两个操作数执行二进制数字提升(§5.6.2),将它们都保留为长型或整型。操作的类型将是(提升的)操作数的类型。此时,&将是按位与,^将是按位异或,|将是按位异或。(§15.22.1)

如果操作数是布尔型或布尔型,操作数将在必要时进行开箱转换(§5.1.8),操作类型将为布尔型。如果两个操作数都为真,&将返回真;如果两个操作数不同,^将返回真;如果其中一个操作数为真,|将返回真。(§15.22.2)

相反,&&是“条件与操作符”(§15.23),||是“条件与操作符”(§15.24)。它们的语法定义为:

ConditionalAndExpression:
  InclusiveOrExpression 
  ConditionalAndExpression && InclusiveOrExpression

ConditionalOrExpression:
  ConditionalAndExpression 
  ConditionalOrExpression || ConditionalAndExpression

&&类似于&,除了它只在左操作数为真时计算右操作数。||类似于|,除了它只在左操作数为false时计算右操作数。

条件-并且具有以下属性:

The conditional-and operator is syntactically left-associative (it groups left-to-right). The conditional-and operator is fully associative with respect to both side effects and result value. That is, for any expressions a, b, and c, evaluation of the expression ((a) && (b)) && (c) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression (a) && ((b) && (c)). Each operand of the conditional-and operator must be of type boolean or Boolean, or a compile-time error occurs. The type of a conditional-and expression is always boolean. At run time, the left-hand operand expression is evaluated first; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8). If the resulting value is false, the value of the conditional-and expression is false and the right-hand operand expression is not evaluated. If the value of the left-hand operand is true, then the right-hand expression is evaluated; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8). The resulting value becomes the value of the conditional-and expression. Thus, && computes the same result as & on boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

条件-或具有以下属性:

The conditional-or operator is syntactically left-associative (it groups left-to-right). The conditional-or operator is fully associative with respect to both side effects and result value. That is, for any expressions a, b, and c, evaluation of the expression ((a) || (b)) || (c) produces the same result, with the same side effects occurring in the same order, as evaluation of the expression (a) || ((b) || (c)). Each operand of the conditional-or operator must be of type boolean or Boolean, or a compile-time error occurs. The type of a conditional-or expression is always boolean. At run time, the left-hand operand expression is evaluated first; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8). If the resulting value is true, the value of the conditional-or expression is true and the right-hand operand expression is not evaluated. If the value of the left-hand operand is false, then the right-hand expression is evaluated; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8). The resulting value becomes the value of the conditional-or expression. Thus, || computes the same result as | on boolean or Boolean operands. It differs only in that the right-hand operand expression is evaluated conditionally rather than always.

简而言之,正如@JohnMeagher在评论中反复指出的那样,&和|实际上在操作数为布尔或布尔的特定情况下是非短路布尔操作符。通过良好的实践(即:没有次要影响),这是一个微小的差异。然而,当操作数不是布尔值或布尔值时,操作符的行为就大不相同了:位操作和逻辑操作在Java编程的高层中根本无法进行比较。

非短路是有用的。有时你想确保两个表达式都有值。例如,假设您有一个从两个单独的列表中删除对象的方法。你可能想这样做:

class foo {

    ArrayList<Bar> list1 = new ArrayList<Bar>();
    ArrayList<Bar> list2 = new ArrayList<Bar>();

    //Returns true if bar is removed from both lists, otherwise false.
    boolean removeBar(Bar bar) {
        return (list1.remove(bar) & list2.remove(bar));
    }
}

如果您的方法改为使用条件操作数,如果第一个列表返回false,则它将无法从第二个列表中删除对象。

//Fails to execute the second remove if the first returns false.
boolean removeBar(Bar bar) {
    return (list1.remove(bar) && list2.remove(bar));
}

它并不是特别有用,并且(与大多数编程任务一样)您可以通过其他方法实现它。但这是位操作数的一个用例。