Почему Java не имеет составных версий условных и условных операторов или операторов? (&& =, || =)

Итак, для двоичных операторов на булевых языках 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];

Ответ 1

Возможно, потому что что-то вроде

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

похоже, что он должен присваивать x и оценивать someComplexExpression(), но тот факт, что оценка зависит от значения x, не является очевидной из синтаксиса.

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

Ответ 2

Причина

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

  • подверженной ошибкам
  • бесполезен

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

Если 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, поэтому второй код выше менее подвержен ошибкам.

Else &= достаточно, потому что разработчик хочет, чтобы 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 ...

Ответ 3

Именно так в Java, потому что это так в C.

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

Но вторая часть моего ответа не имеет источников для его резервного копирования.

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

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

На самом деле не могу придумать, почему.

Ответ 8

Разрешено в Ruby.

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

Ответ 9

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

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

Вы считаете, что они одинаковы?

Ответ 10

Я не могу думать ни о какой лучшей причине, тогда "Это выглядит невероятно уродливо!"

Ответ 11

&

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

& &

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

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

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