Почему в Java нет составных версий условных и условных операторов?(&& =, || =) - PullRequest
77 голосов
/ 24 февраля 2010

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

Давайте подведем краткий обзор того, что они делают здесь:

Для & результирующее значение равно true, если оба значения операнда равны true; в противном случае результат будет false.

Для | результирующее значение равно false, если оба значения операнда равны false; в противном случае результат будет true.

Для ^ результирующее значение равно true, если значения операндов различны; в противном случае результат будет false.

Оператор && похож на &, но оценивает его правый операнд, только если значение его левого операнда равно true.

Оператор || похож на |, но оценивает его правый операнд, только если значение его левого операнда равно false.

Теперь среди всех 5, 3 из них имеют составные версии назначений, а именно |=, &= и ^=. Таким образом, мой вопрос очевиден: почему Java также не обеспечивает &&= и ||=? Я нахожу, что мне нужно больше, чем мне нужно &= и |=.

И я не думаю, что «потому что это слишком долго» - хороший ответ, потому что у Java есть >>>=. Должна быть более веская причина для этого упущения.


С 15,26 Операторы присваивания :

Есть 12 операторов присваивания; [...] = *= /= %= += -= <<= >>= >>>= &= ^= |=


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

С 15.26.2 Составные операторы присваивания :

Составное выражение присваивания в форме E1 op= E2 эквивалентно E1 = (T)((E1) op (E2)), где T - это тип E1, за исключением того, что E1 вычисляется только один раз.

В качестве доказательства следующий фрагмент кода выдает NullPointerException, а не ArrayIndexOutOfBoundsException.

    int[] a = null;
    int[] b = {};
    a[0] += b[-1];

Ответы [ 11 ]

25 голосов
/ 29 марта 2012

Причина

Операторы &&= и ||= недоступны на Java , поскольку для большинства разработчиков эти операторы:

  • подверженные ошибки
  • 1012 * бесполезен *

Пример для &&=

Если в Java разрешен оператор &&=, то этот код:

bool isOk = true; //becomes false when at least a function returns false
isOK &&= f1();
isOK &&= f2(); //we may expect f2() is called whatever the f1() returned value

будет эквивалентно:

bool isOk = true;
if (isOK) isOk = f1();
if (isOK) isOk = f2(); //f2() is called only when f1() returns true

Этот первый код подвержен ошибкам , потому что многие разработчики подумают, что f2() всегда вызывается независимо от возвращаемого значения f1 (). Это как bool isOk = f1() && f2();, где f2() вызывается только тогда, когда f1() возвращает true.

Если разработчик хочет, чтобы f2() вызывался только тогда, когда f1() возвращает true, следовательно, второй код выше менее подвержен ошибкам.

Остальное &= достаточно, потому что разработчик хочет, чтобы f2() всегда вызывался:

Тот же пример, но для &=

bool isOk = true;
isOK &= f1();
isOK &= f2(); //f2() always called whatever the f1() returned value

Кроме того, JVM должна выполнить приведенный выше код как следующий:

bool isOk = true;
if (!f1())  isOk = false;
if (!f2())  isOk = false;  //f2() always called

Сравнить && и & Результаты

Являются ли результаты операторов && и & одинаковыми при применении к логическим значениям?

Давайте проверим, используя следующий код Java:

public class qalcdo {

    public static void main (String[] args) {
        test (true,  true);
        test (true,  false);
        test (false, false);
        test (false, true);
    }

    private static void test (boolean a, boolean b) {
        System.out.println (counter++ +  ") a=" + a + " and b=" + b);
        System.out.println ("a && b = " + (a && b));
        System.out.println ("a & b = "  + (a & b));
        System.out.println ("======================");
    }

    private static int counter = 1;
}

Выход:

1) a=true and b=true
a && b = true
a & b = true
======================
2) a=true and b=false
a && b = false
a & b = false
======================
3) a=false and b=false
a && b = false
a & b = false
======================
4) a=false and b=true
a && b = false
a & b = false
======================

Поэтому ДА мы можем заменить && на & для логических значений ;-)

Так что лучше используйте &= вместо &&=.

То же самое для ||=

Те же причины, что и для &&=:
оператор |= менее подвержен ошибкам, чем ||=.

Если разработчик хочет, чтобы f2() не вызывался, когда f1() возвращает true, тогда я советую следующие альтернативы:

// here a comment is required to explain that 
// f2() is not called when f1() returns false, and so on...
bool isOk = f1() || f2() || f3() || f4();

или

// here the following comments are not required 
// (the code is enough understandable)
bool isOk = false;
if (!isOK) isOk = f1();
if (!isOK) isOk = f2(); //f2() is not called when f1() returns false
if (!isOK) isOk = f3(); //f3() is not called when f1() or f2() return false
if (!isOK) isOk = f4(); //f4() is not called when ...
16 голосов
/ 24 февраля 2010

Наверное, потому что что-то вроде

x = false;
x &&= someComplexExpression();

выглядит так, как будто его следует присвоить x и оценить someComplexExpression(), но тот факт, что оценка зависит от значения x, не очевиден из синтаксиса.

Кроме того, поскольку синтаксис Java основан на C, и никто не видел острой необходимости добавлять эти операторы. В любом случае, вам, вероятно, будет лучше с оператором if.

9 голосов
/ 01 октября 2009

Именно так в Java, потому что так в Си.

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

Но во второй части моего ответа нет источников, подтверждающих это.

4 голосов
/ 24 февраля 2010

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

Интересно, что такие языки, как ruby ​​ do , имеют || = и && =.

Редактировать: терминология отличается между Java и C

4 голосов
/ 01 октября 2009

Одна из оригинальных целей Java должна была быть «простой, объектно-ориентированной и знакомой». Применительно к этому случаю & = знакомо (у C, C ++ оно есть и знакомо в этом контексте означает знакомое для того, кто знает эти два).

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

3 голосов
/ 21 февраля 2013

Для логических переменных && и || будет использовать оценку короткого замыкания, а & и | нет, поэтому можно ожидать, что && = и || = также будут использовать оценку короткого замыкания. Для этого есть хороший вариант использования. Особенно, если вы перебираете цикл, вы хотите быть быстрым, эффективным и лаконичным.

Вместо записи

foreach(item in coll)
{
   bVal = bVal || fn(item); // not so elegant
}

Я хочу написать

foreach(item in coll)
{
  bVal ||= fn(item);    // elegant
}

и знайте, что если bVal истинно, функция fn () не будет вызываться до конца итераций.

2 голосов
/ 01 октября 2009

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

Я согласен, что есть больше смысла в существовании, но это не так уж плохо, если его там нет. Я думаю, его там не было, потому что у С его нет.

Действительно не могу понять, почему.

0 голосов
/ 12 июня 2015

&

проверяет оба операнда, это побитовый оператор. Java определяет несколько побитовых операторов, которые могут применяться к целочисленным типам, long, int, short, char и byte.

&&

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

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

Наличие оператора присваивания && = не добавит новые функциональные возможности в язык. Арифметика побитового оператора намного более выразительна, вы можете сделать целочисленную побитовую арифметику, которая включает в себя булеву арифметику. Логические операторы могут просто выполнять булеву арифметику.

0 голосов
/ 01 октября 2009

Я не могу придумать более веской причины, чем «Это выглядит невероятно безобразно!»

0 голосов
/ 01 октября 2009

a & b и a && b - это не одно и то же.

a && b - логическое выражение, которое возвращает логическое значение, а a & b - побитовое выражение, которое возвращает целое число (если a и b - целые числа).

Как вы думаете, они одинаковы?

...