我只是想知道为什么我们通常在两个布尔值之间使用逻辑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

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


当前回答

其他答案很好地涵盖了运算符之间的函数差异,但这些答案可以适用于目前存在的几乎每一种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编程的高层中根本无法进行比较。

其他回答

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

还要注意一个常见的陷阱:非惰性操作符优先于惰性操作符,因此:

boolean a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c

混合的时候要小心。

|是位运算符:||是短路运算符——当一个元素为假时,它将不检查其他元素。

 if(something || someotherthing)
 if(something | someotherthing)

如果某个值为TRUE, ||将不会计算另一个值,而|可以。如果If语句中的变量实际上是函数调用,那么使用||可能会节省大量性能。

你唯一会使用|或&而不是||或&&的时候是当你有非常简单的布尔表达式,并且捷径的成本(即分支)大于你不计算后面的表达式所节省的时间。

然而,这是一种微优化,除了在最底层的代码中,它很少起作用。

除了短路之外,另一件需要记住的事情是,对可能不是0或1的值执行位逻辑操作与条件逻辑具有非常不同的含义。虽然|和||通常是一样的,但使用&和&&你会得到非常不同的结果(例如2 & 4是0/假,而2 && 4是1/真)。

如果你从一个函数中得到的东西实际上是一个错误代码,而你正在测试非0,这可能会很重要。

在Java中,这不是一个大问题,因为你必须显式地将类型转换为布尔值或与0进行比较,但在其他具有类似语法的语言(C/ c++等)中,这可能相当令人困惑。

另外,请注意&和|只能应用于整数类型的值,而不是所有可以等效于布尔测试的值。同样,在非java语言中,有相当多的东西可以用作带有隐式!= 0比较的布尔值(指针、浮点数、带有操作符bool()的对象等),而位操作符在这些上下文中几乎总是毫无意义的。