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

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

Я имею в виду, посмотрите на следующее:

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

больше информации

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

К тому же, | может использоваться для выполнения операции побитового ИЛИ со значениями байтов / коротких / целых / длинных. || не могу.

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

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

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

С помощью | а также & вместо этого может привести к NullPointerException быть брошенным здесь.

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

Например:

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/ ложное время 2 && 4 1/ правда).

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

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

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

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

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

А | б: оценить б в любом случае

|| b: оценивать b, только если a оценивается как ложное

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

boolean a = true;
boolean b = false;

if (a || b) {
}

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

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

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

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

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

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

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

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

| is the binary or operator

|| is the logic or operator

Примечание: у Java есть |=, но нет ||=

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

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

Другие ответы хорошо справились с функциональной разницей между операторами, но ответы могут относиться практически ко всем существующим на сегодняшний день 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 не включает в себя примитивные типы, определение примитивных типов в конечном счете требуется, так как они могут быть типом измерения для массива, который является ReferenceType.)

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

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

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

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

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

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

ConditionalAndExpression:
  InclusiveOrExpression 
  ConditionalAndExpression && InclusiveOrExpression

ConditionalOrExpression:
  ConditionalAndExpression 
  ConditionalOrExpression || ConditionalAndExpression

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

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

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

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

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

Короче говоря, как @JohnMeagher неоднократно указывал в комментариях, & а также | на самом деле, это недолговечные логические операторы в конкретном случае, когда boolean или же Boolean, С хорошими практиками (то есть: никакие вторичные эффекты), это незначительная разница. Когда операнды не boolean с или Boolean Однако операторы ведут себя совершенно по- разному: побитовые и логические операции просто плохо сравниваются на высоком уровне программирования Java.

1).(Выражение1 | выражение2), | Оператор будет оценивать 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). (Выражение1 || выражение2), || Оператор не будет оценивать 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;
    }
}

|| возвращает логическое значение, используя два значения ИЛИ (поэтому его называют ЛОГИЧЕСКИМ или)

IE:

if (A || B) 

Вернет true, если A или B - true, или false, если они оба false.

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

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

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

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

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

Основное различие между ними заключается в том, что | сначала преобразует значения в двоичные, затем выполняет битовую обработку или операцию. Между тем, || не преобразует данные в двоичный файл, а просто выполняет выражение или в исходном состоянии.

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

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

Например,

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

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

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

Надеюсь это поможет.

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

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.

|| Сценарий, когда левая сторона истинна [if(a||bool())]

выход "If condition executed"

|| Сценарий, когда левая сторона ложна [if(b||bool())]

Выход-

Bool
If condition executed

Conclusion of || При использовании || Правая сторона проверяет только когда левая сторона ложна.

| Сценарий, когда левая сторона истинна [if(a|bool())]

Выход-

Bool
If condition executed

| Сценарий, когда левая сторона ложна [if(b|bool())]

Выход-

Bool
If condition executed

Conclusion of | При использовании | проверьте как левую, так и правую сторону.

После внимательного прочтения этой темы мне все еще непонятно, использую ли | как логический оператор соответствует практике шаблонов Java.

Недавно я изменил код в запросе на вытягивание, обращаясь к комментарию, где

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

пришлось изменить на

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

Какая на самом деле принятая версия?

Документация Java не упоминает| как логический оператор ИЛИ без короткого замыкания.

Не заинтересованы в голосовании, а больше в выяснении стандарта?! Обе версии кода компилируются и работают должным образом.

| = побитовый или, || = логика или

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

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

он напечатает в секунду, если
х это: 10

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

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

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

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

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

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

Взгляни на:

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

| поразрядно включается ИЛИ

|| логично ИЛИ

Операторы Java

| побитовый или, || логично или.

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

Один займет два бита и / или их.

Кто-то определит истину (это ИЛИ это). Если это правда или это правда, тогда ответ верен.

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

Другие вопросы по тегам