Почему мы обычно используем ` | / ` не`/', в чем разница?

мне просто интересно, почему мы обычно используем логическое или || между двумя логическими не побитовыми или |, хотя они оба хорошо работают.

Я имею в виду следующее:

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

можем ли мы использовать | вместо ||? То же самое с & и &&.

27 ответов


если вы используете || и && "формы", а не | и & формы этих операторов, 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()
}

подробнее


| не выполняет оценку короткого замыкания в булевых выражениях. || прекратит оценку, если первый операнд равен true, но | не будет.

кроме того, | может использоваться для выполнения побитовой операции или для значений byte/short/int/long. || не может.


таким образом, чтобы построить на других ответах с примером, короткое замыкание имеет решающее значение в следующих защитных проверках:

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

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

используя | и & вместо этого может привести к NullPointerException бросили здесь.


логическое || и && проверяем правую сторону только при необходимости. The | и & проверьте оба все время.

например:

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 doesn't = 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 a, b, c;
a || b && c; //resolves to a || (b && c)
a | b && c; //resolves to (a | b) && c

будьте осторожны при их смешивании.


в дополнение к короткому замыканию, еще одна вещь, которую нужно иметь в виду, заключается в том, что выполнение побитовой логической операции над значениями, которые могут быть отличными от 0 или 1, имеет совсем другое значение, чем условная логика. Хотя обычно это то же самое для | и || С & и && вы получите очень разные результаты (например,2 & 4 равно 0 / false в то время как 2 && 4 is 1 / true).

если то, что вы получаете от функции, на самом деле является кодом ошибки, и вы тестируете для non-0-ness, это может иметь большое значение.

это не такая большая проблема в Java, где вы должны явно typecast в boolean или сравнить с 0 или тому подобное, но в других языках с аналогичным синтаксисом (C/C++ и др.) Это может быть довольно запутанным.

кроме того, обратите внимание, что & и | могут применяться только к целочисленным значениям, а не ко всему, что может быть эквивалентно логическому тесту. Опять же, в языках, отличных от Java, есть довольно много вещей, которые можно использовать как логическое с неявным != 0 сравнение (указатели, поплавки, объекты с operator bool(), etc.) и побитовые операторы почти всегда бессмысленны в этих контекстах.


единственный раз, когда вы будете использовать | или & вместо || или && - это когда у вас есть очень простые логические выражения, а стоимость короткой резки (т. е. ветви) больше, чем время, которое вы экономите, не оценивая более поздние выражения.

однако это микро-оптимизация, которая редко имеет значение, за исключением кода самого низкого уровня.


/ / - логический оператор or, а / - побитовый оператор or.

boolean a = true;
boolean b = false;

if (a || b) {
}

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

В дополнение к тому, что | является побитовым оператором: / / является оператором короткого замыкания-когда один элемент ложен, он не будет проверять другие.

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

если что-то является правдой, || не оценить someotherthing, пока не будет делать. Если переменные в ваших if-операторах на самом деле являются вызовами функций, использование||, возможно, сохраняет большую производительность.


a/ b: оценить b в любой случае

a | / b: оценить b только если a оценивает значение false


| is the binary or operator

|| is the logic or operator

операторы || и && называют условных операторов, а | и & называют побитовые операторы. Они служат разным целям.

условные операторы работают только с выражениями, которые статически оцениваются как boolean С левой и правой сторон.

побитовые операторы работают с любыми числовыми операндами.

если вы хотите провести логическое сравнение, вы должны использовать условных операторов, так как вы добавите какой-то тип безопасности в свой код.


боковое Примечание: Java имеет |= но не|/=

пример того, когда вы должны использовать||, когда первое выражение является тестом, чтобы увидеть, взорвется ли второе выражение. например, использование одного / в следующем случае hte может привести к NPE.

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

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), || оператор не будет оценивать expression2, если expression1 имеет значение true.

пример:

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

/ / возвращает логическое значение путем OR'ING два значения (вот почему его называют логическим или)

IE:

if (A || B) 

вернет true, если A или B истинны, или false, если они оба ложны.

/ - оператор, выполняющий побитовую операцию над двумя значениями. Чтобы лучше понять побитовые операции, вы можете прочитать здесь:

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


одно основное различие заключается в том, что || и && показывают "короткое замыкание", поэтому RHS будет оцениваться только при необходимости.

, например,

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

выше, если a истинно, то b не будет проверяться и выполняется path1. Если | был использован, то обе стороны будут оценены, даже если " a " истинно.

посмотреть здесь и здесь, для получения дополнительной информации.

надеюсь, что это помогает.


Non короткое замыкание может быть полезно. Иногда вы хотите убедиться,что два выражения оценивают. Например, скажем, у вас есть метод, который удаляет объект из двух отдельных списков. Возможно, вы захотите сделать что-то вроде этого:

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

это не удивительно полезно, и (как и в большинстве задач программирования) вы могли бы достичь этого другими средствами. Но это дело битовые операнды.


другие ответы проделали хорошую работу, чтобы покрыть функциональную разницу между операторами, но ответы могут применяться практически к каждому c-производному языку, существующему сегодня. Вопрос помечен тегом java, и поэтому я постараюсь ответить конкретно и технически для языка Java.

& и | может быть как целочисленные операторы побитовых и логических операторов. Синтаксис для побитового и логического Операторы (§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.3, соответственно. ShiftExpression требует AdditiveExpression определена в §15.18, который продолжает детализировать, определяя основную арифметику, унарные операторы и т. д. ReferenceType обращается ко всем различные способы представления типа. (А ReferenceType не включает примитивные типы, определение примитивных типов в конечном счете требуется, поскольку они могут быть типом измерения для массива, который is a ReferenceType.)

побитовые и логические операторы имеют следующие свойства:

  • эти операторы имеют разный приоритет, с & имея самый высокий приоритет и | самые низкие старшинство.
  • каждый из этих операторов синтаксически левоассоциативны (каждой группы слева направо).
  • каждый оператор является коммутативным, если выражения операнда не имеют побочных эффектов.
  • каждый оператор ассоциативность.
  • побитовые и логические операторы могут использоваться для сравнения двух операндов числового типа или двух операндов типа boolean. Все остальные случаи приводят к ошибке времени компиляции.

различие между тем, является ли оператор побитовым оператором или логическим оператором, зависит от того, являются ли операнды "конвертируемыми в примитивный интегральный тип" (§4.2) или если они имеют типы boolean или Boolean (§5.1.8).

если операнды являются целочисленными типами, двоичное числовое продвижение (§5.6.2) выполняется на обоих операндах, оставляя их как либо longs или ints для операции. Типом операции будет тип (повышенных) операндов. В этот момент & будет побитовым и,^ будет побитовое исключающее ИЛИ, а | будет побитовым включительно или. (§15.22.1)

если операнды boolean или Boolean, операнды будут подлежать распаковке преобразования при необходимости (§5.1.8), и тип операции будет boolean. & в результате true если оба операнда true, ^ в результате true если оба операнда разные, и | в результате true если любой операнд true. (§15.22.2)

в противоположность && является "условно-и оператор" (§15.23) и || является оператором "Conditional-Or" (§15.24). Их синтаксис определяется как:

ConditionalAndExpression:
  InclusiveOrExpression 
  ConditionalAndExpression && InclusiveOrExpression

ConditionalOrExpression:
  ConditionalAndExpression 
  ConditionalOrExpression || ConditionalAndExpression

&& как &, за исключением того, что это вычисляет только правый операнд, если левый операнд равен true. || как |, за исключением того, что он оценивает только правый операнд, если левый операнд false.

условно-и имеет следующие свойства:

  • условный оператор является синтаксически левоассоциативны (это группы слева направо).
  • оператор conditional-and полностью ассоциативен по отношению как к побочным эффектам, так и к результату значение. То есть для любых выражений a, b и c, оценка выражения ((a) && (b)) && (c) дает тот же результат, с теми же побочными эффектами, происходящими в том же порядке, как и оценка выражения (a) && ((b) && (c)).
  • каждый операнд оператора conditional-and должен иметь тип boolean или Boolean, или ошибка времени компиляции происходит.
  • тип условного и выражения всегда boolean.
  • во время выполнения сначала вычисляется выражение левого операнда; если результат имеет тип Boolean, это подвергается распаковыванию преобразования (§5.1.8).
  • если полученное значение false, значение условного-и выражения равно false и выражение правого операнда не вычисляется.
  • если значение левого операнда true, затем вычисляется правое выражение; если результат имеет тип Boolean, это подвергается распаковыванию преобразования (§5.1.8). Полученное значение становится значением выражения conditional-and.
  • таким образом, && вычисляет тот же результат, что и & on boolean операнды. Он отличается только тем, что выражение правого операнда оценивается условно, а не всегда.

условно-или имеет следующие свойства:

  • в условное или оператор синтаксически левоассоциативны (это группируется слева направо).
  • оператор conditional-or полностью ассоциативен как по побочным эффектам, так и по значению результата. То есть для любых выражений a, b и c, оценка выражения ((a) || (b)) || (c) дает тот же результат, с теми же побочными эффектами, происходящими в том же порядке, как и оценка выражения (a) || ((b) || (c)).
  • каждый операнд оператор conditional-or должен иметь тип boolean или Boolean, или ошибка времени компиляции происходит.
  • тип условного или выражения всегда boolean.
  • во время выполнения сначала вычисляется выражение левого операнда; если результат имеет тип Boolean, это подвергается распаковыванию преобразования (§5.1.8).
  • если полученное значение true, значение выражения conditional-or равно true и выражение операнда правой руки не вычисляется.
  • если значение левого операнда false, затем вычисляется правое выражение; если результат имеет тип Boolean, это подвергается распаковыванию преобразования (§5.1.8). Полученное значение становится значением условного выражения.
  • таким образом, || вычисляет тот же результат, что и | on boolean или Boolean операнды. Он отличается только тем, что правая рука выражение операнда вычисляется условно, а не всегда.

короче говоря, как неоднократно указывал @JohnMeagher в комментариях,& и | являются, по сути, не-короткозамыкающими булевыми операторами в конкретном случае операндов, являющихся либо boolean или Boolean. При хорошей практике (т. е. без вторичных эффектов) это незначительное различие. Когда операнды не booleanили Booleans, однако, операторы ведут себя очень differently: побитовые и логические операции просто не сравниваются хорошо на высоком уровне программирования 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 | при использовании |, проверьте как левую, так и правую сторону.


| = побитовое или || = логика или


обычно я использую, когда есть оператор pre increment и post increment. Посмотрите на следующий код:

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 is: 10

и if блоки одинаковы, но результат другой. когда есть |, оба условия будут оценены. Но если это так ... --3-->, он не будет оценивать второй условие как первое условие уже истинно.


есть много вариантов использования, предполагающих, почему вы должны пойти на ||, а не | . Некоторые случаи использования обязательно использовать | оператор для проверки всех условий.

например, если вы хотите проверить проверку формы и хотите показать пользователю все недопустимые поля с текстами ошибок, а не только первое недопустимое поле.

|| оператор будет,

   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 условиях.


/ / является логическим или и / немного мудрым или.


операторы Java

| - побитовое или || логическое или.


взгляните на:

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html

/ является побитовым включительно или

|| логично или


| оператор побитового. || является логическим оператором.

один возьмет два бита и или их.

один определит истину (то или это), если это верно или то верно, то ответ истинен.

О, и, черт возьми, люди быстро отвечают на эти вопросы.