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

时间:2011-08-18 03:19:01

标签: java bitwise-operators

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

我们可以使用|代替||吗?与&&&相同。

28 个答案:

答案 0 :(得分: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

答案 1 :(得分:80)

布尔表达式中的

| does not do短路评估。 ||将停止评估第一个操作数是否为真,但|不会。

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

答案 2 :(得分:64)

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

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

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

使用|&可能会导致NullPointerException被抛出。

答案 3 :(得分: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
...

答案 4 :(得分:17)

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

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

混合时要小心。

答案 5 :(得分:15)

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

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

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

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

答案 6 :(得分:9)

您使用|&代替||&&的唯一时间是您有非常简单的布尔表达式和短切割成本(即通过不评估后面的表达式,分支)大于你保存的时间。

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

答案 7 :(得分:8)

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

boolean a = true;
boolean b = false;

if (a || b) {
}

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

答案 8 :(得分:8)

a | b:在任何案例

中评估b

a || b:仅当> a评估为假

时才评估b

答案 9 :(得分:7)

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

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

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

答案 10 :(得分:3)

| is the binary or operator

|| is the logic or operator

答案 11 :(得分:3)

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

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

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

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

答案 12 :(得分:2)

1)。(expression1 | expression2),|无论expression1的结果是true还是false,operator都会计算expression2。

示例:

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为true,则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;
    }
}

答案 13 :(得分:2)

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

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

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

答案 14 :(得分:2)

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

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

AndExpression:
  EqualityExpression 
  AndExpression & EqualityExpression

ExclusiveOrExpression:
  AndExpression 
  ExclusiveOrExpression ^ AndExpression

InclusiveOrExpression:
  ExclusiveOrExpression 
  InclusiveOrExpression | ExclusiveOrExpression

EqualityExpression的语法在§15.21中定义,§15.20中需要RelationalExpressionShiftExpression需要ReferenceTypeShiftExpression分别在§15.19§4.3中定义。 AdditiveExpression需要在§15.18中定义ReferenceType,其继续向下钻取,定义基本算术,一元运算符等。ReferenceType深入研究表示a的所有各种方法类型。 (虽然ReferenceType不包含基本类型,但最终需要定义基本类型,因为它们可能是数组的维度类型, a &。 )

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

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

运算符作为按位运算符还是逻辑运算符之间的区别取决于操作数是否可以转换为基本整数类型&#34; (§4.2)或类型Booleanlong§5.1.8)。

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

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

相比之下, ConditionalAndExpression: InclusiveOrExpression ConditionalAndExpression && InclusiveOrExpression ConditionalOrExpression: ConditionalAndExpression ConditionalOrExpression || ConditionalAndExpression 是&#34;条件和运营商&#34; (§15.23)和&&是&#34; Conditional-Or Operator&#34; (§15.24)。他们的语法定义为:

&

true||类似,只是如果左操作数为|,则仅评估右操作数。 falsea类似,只是如果左操作数为b,它只评估右操作数。

条件 - 并具有以下属性:

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

Conditional-Or具有以下属性:

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

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

答案 15 :(得分:1)

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

IE:

if (A || B) 

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

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

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

答案 16 :(得分:1)

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

例如

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

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

有关详情,请参阅Herehere

希望这有帮助。

答案 17 :(得分:1)

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

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

答案 18 :(得分:1)

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

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"

  

||方案,当左侧为假[if(b || bool())]

输出-

Bool
If condition executed

Conclusion of || 使用||时,右侧仅检查左侧是否为假。

  

|方案,当左侧为true [if(a | bool())]

输出-

Bool
If condition executed
  

|方案,当左侧为假[if(b | bool())]

输出-

Bool
If condition executed

Conclusion of | 使用|时,请同时检查左侧和右侧。

答案 19 :(得分:1)

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

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

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

答案 20 :(得分: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,并显示错误消息。但是,如果你改成它,

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

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

答案 21 :(得分:0)

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

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

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

必须更改为

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

实际接受的版本是什么?

  

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

对投票不感兴趣,但是对找出标准感兴趣吗? 两种代码版本都可以按预期进行编译和工作。

答案 22 :(得分:0)

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

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

输出:

  

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

  如果是,它将在第二次打印   x是:10

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

答案 23 :(得分:0)

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

答案 24 :(得分:-1)

答案 25 :(得分:-1)

Java operators

|是按位或,||是合乎逻辑的。

答案 26 :(得分:-1)

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

答案 27 :(得分:-2)

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

一个会占用两位和/或它们。

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

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