为什么我们通常使用`||`而不是`|`,有什么区别?

问题描述 投票:206回答:27

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

我们可以使用|而不是||吗?与&&&相同。

java bitwise-operators
27个回答
335
投票

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

这是一个问题,如果你想要短路评估 - 大部分时间你想要。

说明短路益处的一个好方法是考虑以下示例。

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

正如杰里米和彼得提到的那样,短路的另一个好处是空参考检查:

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

more info


7
投票

除了|的事实是一个按位运算符:||是一个短路运算符 - 当一个元素为假时,它不会检查其他元素。

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

如果某事是真的,||不会评估某些事情,而|会做。如果if语句中的变量实际上是函数调用,则使用||可能会节省很多性能。


3
投票
| is the binary or operator

|| is the logic or operator

3
投票

运算符||&&称为条件运算符,而|&称为位运算符。它们用于不同的目的。

条件运算符仅适用于在左侧和右侧静态求值为boolean的表达式。

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

如果要执行逻辑比较,则应使用条件运算符,因为您将为代码添加某种类型的安全性。


2
投票

旁注:Java有| =但不是|| =

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

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

2
投票

其他答案在覆盖运算符之间的功能差异方面做得很好,但答案可能适用于当今存在的几乎所有C语言。问题用标记,因此我将尽力为Java语言专门和技术性地回答。

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

AndExpression:
  EqualityExpression 
  AndExpression & EqualityExpression

ExclusiveOrExpression:
  AndExpression 
  ExclusiveOrExpression ^ AndExpression

InclusiveOrExpression:
  ExclusiveOrExpression 
  InclusiveOrExpression | ExclusiveOrExpression

EqualityExpression的语法在§15.21中定义,RelationalExpression需要在§15.20中定义的ShiftExpression,后者又需要分别在ReferenceType§15.19中定义的§4.3ShiftExpressionAdditiveExpression需要在§15.18中定义的ReferenceType,它继续向下钻取,定义基本算术,一元运算符等.ReferenceType深入研究表示类型的各种方法。 (虽然ReferenceType不包含原始类型,但最终需要原始类型的定义,因为它们可能是数组的维度类型,这是一个&。)

Bitwise和Logical运算符具有以下属性:

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

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

如果操作数是整数类型,则对两个操作数执行二进制数字提升(long),将它们作为ints或&s进行操作。操作的类型将是(提升的)操作数的类型。此时,^将为按位AND,|将为按位异或,§15.22.1将为按位包含OR。 (boolean

如果操作数是Boolean§5.1.8,操作数将在必要时进行拆箱转换(boolean),操作类型为&。如果两个操作数都是truetrue将导致^,如果两个操作数不同,true将导致|,如果任一操作数是truetrue将导致§15.22.2。 (&&

相比之下,§15.23是“条件和运算符”(||),而§15.24是“条件运算符”(ConditionalAndExpression: InclusiveOrExpression ConditionalAndExpression && InclusiveOrExpression ConditionalOrExpression: ConditionalAndExpression ConditionalOrExpression || ConditionalAndExpression )。他们的语法定义为:

&&

&就像true,除了它只评估右操作数,如果左操作数是|||就像false,除了它只评估右操作数,如果左操作数是a

条件 - 并具有以下属性:

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

Conditional-Or具有以下属性:

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

简而言之,正如@JohnMeagher在评论中反复指出的那样,|boolean实际上是操作数为Booleanboolean的特定情况下的非短路布尔运算符。通过良好实践(即:没有次要影响),这是一个微小的差异。但是,当操作数不是Booleans或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; } } s时,运算符的行为非常不同:按位和逻辑运算在Java编程的高级别上不能很好地比较。


2
投票

1)。(expression1 | expression2),|无论expression1的结果是true还是false,operator都将计算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;
    }
}

2)。(expression1 || expression2),||如果expression1为true,则operator不会计算expression2。

例:

if (A || B) 

1
投票

||通过对两个值进行OR运算来返回一个布尔值(这就是为什么它被称为LOGICAL或者)

IE:

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

如果A或B为真,则返回true;如果它们都为假,则返回false。

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

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


1
投票

一个主要区别是||和&&表现出“短路”,因此只有在需要时才会评估RHS。

对于例如

Here

如果a为真,则上面不会测试b并且执行path1。如果|如果使用,那么即使'a'是真的,也会对双方进行评估。

有关更多信息,请参阅hereclass 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)); } }

希望这可以帮助。


1
投票

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

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

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

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

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


1
投票

它们之间的基本区别在于|首先将值转换为二进制,然后执行bit wise或operation。同时,||不会将数据转换为二进制文件,只是对其原始状态执行或表达式。

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


80
投票

| does not do布尔表达式中的短路评估。 ||将停止评估第一个操作数是否为真,但|不会。

此外,|可用于对byte / short / int / long值执行按位或运算。 ||不能。


1
投票

当我有这个问题时,我创建了测试代码来了解这一点。

||

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

"If condition executed"场景,当左侧为真[if(a || bool())]

输出||

Bool If condition executed 场景,当左侧为假[if(b || bool())]

输出 -

Conclusion of ||

||当使用|时,右侧只检查左侧是否为假。

Bool If condition executed 场景,当左侧为真[if(a | bool())]

输出 -

|

Bool If condition executed 场景,当左侧为假[if(b | bool())]

输出 -

Conclusion of |

|使用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); } } } 时,请检查左侧和右侧。


0
投票

| =按位或,|| =逻辑或


0
投票

通常我在有预增量和后增量运算符时使用。看下面的代码:

if

输出:

它会先打印出来 我是:11 它将在第二个打印if x是:10

两个|块都相同但结果不同。当有||时,两种条件都将被评估。但如果它是||,它将不会评估第二个条件,因为第一个条件已经成立。


0
投票

有许多用例表明你为什么要选择|而不是|。一些用例必须使用||运算符来检查所有条件。

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

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

因此,使用上面的代码片段,如果用户使用ALL空字段提交表单,则仅显示 if(checkIfEmpty(nameField) | checkIfEmpty(phoneField) | checkIfEmpty(emailField)) { // invalid form with one or more empty fields } ,并显示错误消息。但是,如果你改成它,

true

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


-1
投票

||是一个逻辑或和|是有点明智的。


-1
投票

-1
投票

看一眼:

qazxswpoi

|是按位包含OR

||逻辑或


-2
投票

|是一个按位运算符。 ||是一个逻辑运算符。

一个将需要两位和/或它们。

一个人将确定真相(这个或那个)如果这是真的或那是真的,那么答案是正确的。

哦,当时人们快速回答这些问题。


64
投票

因此,仅仅通过一个例子来建立其他答案,短路在以下防御性检查中至关重要:

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

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

使用|&可能会导致NullPointerException被扔到这里。


38
投票

逻辑||&&仅在必要时检查右侧。 |&每次检查两侧。

例如:

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
...

17
投票

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

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

混合时要小心。


15
投票

除了短路之外,还要记住的另一件事是对0或1以外的值进行按位逻辑运算与条件逻辑的含义非常不同。虽然它对于|||来说是相同的,但是使用&&&会得到非常不同的结果(例如2 & 4为0 / false而2 && 4为1 / true)。

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

这在Java中并不是一个问题,你必须明确地将其转换为布尔值或与0等进行比较,但在其他具有类似语法的语言(C / C ++等)中,它可能会非常混乱。

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


9
投票

唯一一次使用|&而不是||&&就是当你有非常简单的布尔表达式时,短切割(即分支)的成本大于你通过不评估后面的表达式而节省的时间。

然而,这是一个微优化,除了最低级别的代码之外很少重要。


8
投票

||是|的逻辑或运算符是按位或运算符。

boolean a = true;
boolean b = false;

if (a || b) {
}

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

8
投票

a | b:无论如何评估b

a || b:仅在评估为false时评估b

© www.soinside.com 2019 - 2024. All rights reserved.