为什么我们通常用|| / |?有什么不同?

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

我们可以用|代替||吗?&&&也是如此。

117587 次浏览
| is the binary or operator


|| is the logic or operator

| =位或,|| =逻辑或

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

Java操作符

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

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

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

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

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

||是逻辑或运算符,|是位或运算符。

boolean a = true;
boolean b = false;


if (a || b) {
}


int a = 0x0001;
a = a | 0x0002;

| 不做短路计算布尔表达式。如果第一个操作数为真,||将停止求值,但|不会。

此外,|可用于对字节/短/int/长值执行按位或操作。||不能。

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

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

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

||通过OR'ing两个值返回布尔值(这就是为什么它被称为逻辑或)

即:

if (A || B)

如果A或B中有一个为真则返回真,如果它们都为假则返回假。

|是一个对两个值执行位操作的运算符。为了更好地理解位操作,你可以阅读这里:

http://en.wikipedia.org/wiki/Bitwise_operation

a | b:在任何情况下计算b

a || b: evaluate b 只有在 a的结果为false

附注:Java有|=,但没有||=

必须使用||的一个例子是,当第一个表达式是测试第二个表达式是否会爆炸时。例:在以下情况下使用单个|可能导致NPE。

public static boolean isNotSet(String text) {
return text == null || text.length() == 0;
}

如果你使用的是||&&形式,而不是这些操作符的|&形式,Java将不会费心单独计算右操作数。

这是一个你是否想要在你想要的时间短路求值的问题——大多数

说明短路的好处的一个好方法是考虑下面的例子。

Boolean b = true;
if(b || foo.timeConsumingCall())
{
//we entered without calling timeConsumingCall()
}

正如Jeremy和Peter提到的,短路的另一个好处是空引用检查:

if(string != null && string.isEmpty())
{
//we check for string being null before calling isEmpty()
}

more info

逻辑||&&只在必要时检查右边。|&每次都检查两边。

例如:

int i = 12;
if (i == 10 & i < 9) // It will check if i == 10 and if i < 9
...

重写:

int i = 12;
if (i == 10 && i < 9) // It will check if i == 10 and stop checking afterward because i != 10
...

另一个例子:

int i = 12;
if (i == 12 | i > 10) // It will check if i == 12 and it will check if i > 10
...

重写:

int i = 12;
if (i == 12 || i > 10) // It will check if i == 12, it does, so it stops checking and executes what is in the if statement
...

运算符||&&被称为有条件的运营商,而|&被称为按位运算符。它们有不同的用途。

条件操作符只适用于在左边和右边都静态求值为boolean的表达式。

位操作符适用于任何数字操作数。

如果你想要执行逻辑比较,你应该使用有条件的运营商,因为你将在你的代码中添加某种类型安全。

一个主要的区别是||和&显示“短路”,因此RHS只在需要时进行评估。

如。

if (a || b) {
path1...
} else {
path2..
}

如果a为真,则不会测试b,并执行path1。如果使用|,则即使'a'为真,两边也将被求值。

有关更多信息,请参见在这里在这里

希望这能有所帮助。

因此,在其他答案的基础上,举个例子,短路在以下防御性检查中至关重要:

if (foo == null || foo.isClosed()) {
return;
}


if (bar != null && bar.isBlue()) {
foo.doSomething();
}

而使用|&可能导致在这里抛出NullPointerException

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

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

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

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

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

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

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

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

混合的时候要小心。

通常在有前加和后加运算符时使用。请看下面的代码:

package ocjpPractice;
/**
* @author tithik
*
*/
public class Ex1 {


public static void main(String[] args) {
int i=10;
int j=9;
int x=10;
int y=9;
if(i==10 | ++i>j){
System.out.println("it will print in first if");
System.out.println("i is: "+i);
}


if(x==10 ||++x>y){
System.out.println("it will print in second if");
System.out.println("x is: "+x);
}
}
}

输出:

如果
,它将首先打印 I是:11

如果
,它将在秒内打印 X是:10

两个if块是相同的,但结果不同。 当存在|时,这两个条件都将被计算。但如果它是||,它将不会计算第二个条件,因为第一个条件已经为真。< / p >

1).(expression1 | expression2), |运算符将计算expression2,而不管expression1的结果是真还是假。

例子:

class Or
{
public static void main(String[] args)
{
boolean b=true;


if (b | test());
}


static boolean test()
{
System.out.println("No short circuit!");
return false;
}
}

2).(expression1 || expression2),如果expression1为真,||操作符将不计算expression2。

例子:

class Or
{
public static void main(String[] args)
{
boolean b=true;


if (b || test())
{
System.out.println("short circuit!");
}
}


static boolean test()
{
System.out.println("No short circuit!");
return false;
}
}

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

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));
}

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

有许多用例说明为什么应该使用||而不是|。一些用例必须使用|操作符检查所有条件。

例如,如果你想检查表单验证,你想显示给用户所有带有错误文本的无效字段,而不仅仅是第一个无效字段。

||操作符将是,

   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
}

无论true条件如何,它都会在每个字段上显示正确的错误信息。

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

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

AndExpression:
EqualityExpression
AndExpression & EqualityExpression


ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression ^ AndExpression


InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression | ExclusiveOrExpression

EqualityExpression的语法在§15.21中定义,它需要在RelationalExpression0中定义的RelationalExpression,而RelationalExpression0又需要分别在RelationalExpression1和RelationalExpression2中定义的ShiftExpressionReferenceTypeShiftExpression需要在RelationalExpression3中定义的AdditiveExpression,它继续向下钻取,定义基本算术、一元运算符等。ReferenceType钻取到表示类型的所有不同方式。(虽然ReferenceType不包括基本类型,但基本类型的定义最终是必需的,因为它们可能是数组的维度类型,RelationalExpression4 a ReferenceType。)

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

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

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

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

如果操作数为booleanBoolean,则必要时操作数将进行开箱转换(Boolean1),操作类型将为boolean。如果两个操作数都是true&将得到true;如果两个操作数不同,^将得到true;如果其中一个操作数是true|将得到true。(Boolean2)

相比之下, &&是“条件或操作符”(§15.23),而||是“条件或操作符”(§15.24)。它们的语法定义为:

ConditionalAndExpression:
InclusiveOrExpression
ConditionalAndExpression && InclusiveOrExpression


ConditionalOrExpression:
ConditionalAndExpression
ConditionalOrExpression || ConditionalAndExpression

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

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

  • 条件和操作符在语法上是左关联的(它从左到右分组)。
  • 条件和运算符对于副作用和结果值都是完全关联的。也就是说,对于任何表达式abc,表达式((a) && (b)) && (c)的求值会产生相同的结果,其副作用发生的顺序与表达式(a) && ((b) && (c))的求值相同。
  • 条件与操作符的每个操作数必须为booleanBoolean类型,否则将发生编译时错误。
  • 条件和表达式的类型总是boolean
  • 在运行时,首先计算左操作数表达式;如果结果类型为Boolean,则会进行开箱转换(§5.1.8)。
  • 如果结果值为false,则条件和表达式的值为false,并且不计算右操作数表达式。
  • 如果左操作数的值为true,则计算右操作数的值;如果结果类型为Boolean,则会进行开箱转换(§5.1.8)。结果值成为条件和表达式的值。
  • 因此,&&boolean操作数上计算与&相同的结果。它的不同之处在于右操作数表达式是有条件求值的,而不是总是求值的。

条件-或具有以下属性:

  • 条件或操作符在语法上是左关联的(它从左到右分组)。
  • 条件或操作符对于副作用和结果值都是完全关联的。也就是说,对于任何表达式abc,表达式((a) || (b)) || (c)的求值会产生相同的结果,其副作用发生的顺序与表达式(a) || ((b) || (c))的求值相同。
  • 条件或操作符的每个操作数必须为booleanBoolean类型,否则将发生编译时错误。
  • 条件或表达式的类型总是boolean
  • 在运行时,首先计算左操作数表达式;如果结果类型为Boolean,则会进行开箱转换(§5.1.8)。
  • 如果结果值为true,则条件或表达式的值为true,并且不计算右操作数表达式。
  • 如果左操作数的值为false,则计算右操作数的值;如果结果类型为Boolean,则会进行开箱转换(§5.1.8)。结果值成为条件或表达式的值。
  • 因此,||booleanBoolean操作数上计算与|相同的结果。它的不同之处在于右操作数表达式是有条件求值的,而不是总是求值的。

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

它们之间的基本区别是|首先将值转换为二进制,然后执行按位或操作。同时,||不将数据转换为二进制,只是在其原始状态上执行or表达式。

int two = -2; int four = -4;
result = two | four; // bitwise OR example


System.out.println(Integer.toBinaryString(two));
System.out.println(Integer.toBinaryString(four));
System.out.println(Integer.toBinaryString(result));


Output:
11111111111111111111111111111110
11111111111111111111111111111100
11111111111111111111111111111110

阅读更多:http://javarevisited.blogspot.com/2015/01/difference-between-bitwsie-and-logical.html#ixzz45PCxdQhk

当我遇到这个问题时,我创建了测试代码来了解这个问题。

public class HelloWorld{


public static boolean bool(){
System.out.println("Bool");
return true;
}


public static void main(String []args){


boolean a = true;
boolean b = false;


if(a||bool())
{
System.out.println("If condition executed");
}
else{
System.out.println("Else condition executed");
}


}
}

在这种情况下,我们只改变if条件的左边值加上a或b。

||场景,当左侧为true时[if(a||bool())]

输出"If condition executed"

||场景,当左边为false [if(b||bool())]

输出-

Bool
If condition executed

Conclusion of || 当使用||时,右边只检查左边为假。

|场景,当左侧为true时[if(a|bool())]

输出-

Bool
If condition executed

|场景,当左边为false [if(b|bool())]

输出-

Bool
If condition executed

Conclusion of | 当使用|时,检查左边和右边。

仔细阅读此主题后,我仍然不清楚使用|作为逻辑运算符是否符合Java模式实践。

我最近修改了一个pull请求中的代码

if(function1() | function2()){
...
}

必须改为

boolean isChanged = function1();
isChanged |= function2();
if (isChanged){
...
}

实际接受的版本是什么?

Java文档提到|作为逻辑上非短路的OR运算符。

对投票不感兴趣,更感兴趣的是找出标准?!