Причина существования логических операторов без короткого замыкания - PullRequest
32 голосов
/ 13 февраля 2012

При использовании с boolean операндами & и | становятся логическими операторами на Раздел 15.22.2 JLS .Однако, в отличие от && и ||, они не закорачиваются;они всегда оценивают обе стороны.У меня глупый вопрос: почему менее эффективные логические операторы без короткого замыкания (&, |) все еще там, когда у нас есть более эффективные логические операторы короткого замыкания (&&, * 1013)*)?Я имею в виду, каково реальное использование логических операторов без короткого замыкания, в отличие от логических операторов короткого замыкания?Другими словами, какой смысл всегда оценивать обе стороны, используя логические операторы без короткого замыкания?

Ответы [ 6 ]

27 голосов
/ 13 февраля 2012

Обновленный ответ :

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

Рассмотрим случай, когда вы хотите, чтобы побочные эффекты всегда возникали независимо от того, оценивает ли левое выражение true или false. Например, контраст:

if (foo() & bar()) {
    // Only call this if both operations returned true
}

с

if (foo() && bar()) {
    // Only call this if both operations returned true
}

Предположим, что и foo, и bar имеют эффекты, которые мы хотим, чтобы происходило независимо от того, foo возвращает true или false. В первом примере я знаю , что bar всегда будет вызываться и будет иметь эффект. В последнем, конечно, bar может или не может быть вызван. Если бы у нас не было версии без короткого замыкания, нам пришлось бы использовать временные переменные:

boolean fooResult, barResult;
fooResult = foo();
barResult = bar();
if (fooResult && barResult) {
    // ...
}

Вы можете утверждать (я, вероятно, хотел бы), что вы должны сделать это в любом случае , потому что слишком легко неправильно прочитать if (foo() & bar()), но мы идем, прагматическая причина отсутствия короткого замыкания версии.

Оригинальный ответ :

Как бы вы предложили & (или |) быть оператором с коротким замыканием? С && и || это имеет смысл, потому что вы имеете дело с булевыми условиями: они могут быть истинными или ложными, оттенки серого отсутствуют. Но & и | имеют дело с битами, а не с логическими значениями. Результатом является число. Я имею в виду, я думаю, & не мог бы оценить правую сторону, если бы левая сторона была 0, и аналогично | не мог бы оценить это, если бы левая сторона была полностью битовой для любого тип был, но я не вижу особого смысла делать один крайний случай каждого оператора значимым (по сравнению с 254 или более другими случаями).

12 голосов
/ 13 февраля 2012

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

while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) {

    // re-prompt

}

Если второе условие не было оценено из-за короткого замыкания, attempts никогда не будет увеличено. Таким образом, обеспечивается большая гибкость программиста.

2 голосов
/ 08 декабря 2014

Мой случай (C ++):

void setFields(Parameters bundle)
{
  if (setIfDifferent(&field1, bundle.value1) | 
      setIfDifferent(&field2, bundle.value2) |
      setIfDifferent(&field3, bundle.value3)) {
    storeState();
  }
}

setIfDifferent () устанавливает поле объекта с новым значением, если они различаются, и в этом случае оно возвращает true;или возвращает false, если поле и новое значение совпадают.Итак, мы хотим попытаться установить все поля, и если любое из них изменилось, мы хотим сохранить состояние нового объекта.

1 голос
/ 13 февраля 2012

Вы можете иметь некоторые побочные эффекты в логическом выражении, например, вы можете назначить одновременно с проверкой.Это может работать неправильно, если оценивается только одна часть.

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

Хммм.... Ниже приведен НЕПРАВИЛЬНЫЙ пример, который не будет работать без "не короткого замыкания" ИЛИ:

if( (object1=getInstance1()).getNumber() == 1 || (object2=getInstance2()).getNumber() == 2 ) {

    // do something which requires bot object1 and object2 assigned

}
0 голосов
/ 17 декабря 2015

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

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

Скажи:

if(a = (checkForSomeCondition()) | b = checkForAnotherCondition())
{
 //now do something here with a and b that has been cached
}

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

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

0 голосов
/ 09 июля 2014

В моем случае у меня есть два метода, которые сравнивают два разных, но связанных объекта (Object2 является атрибутом Object1), чтобы увидеть, были ли какие-либо изменения.Обновление должно произойти, если оба из них обновлены, но оба должны быть оценены так, чтобы объекты были изменены, если оба были изменены.Поэтому требуется сравнение по одной трубе «ИЛИ».

EX:

if (compare(object1, currentObject1) | comparison(object2, currentObject2)) {
    updateObject1(object1);
}
...