Почему в 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];

13 ответов

причина

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Брайан Гетц (архитектор языка Java в Oracle) написал:

https://stackru.com/q/2324549/ [этот вопрос] показывает, что есть интерес в наличии этих операторов, и нет четких аргументов, почему они еще не существуют. Поэтому возникает вопрос: обсуждала ли команда JDK добавление этих операторов в прошлом, и если да, то каковы причины против их добавления?

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

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

Я думаю, вы неявно предполагаете (с помощью фразы "есть интерес"), что стоимость близка к нулю, а выгода больше нуля, так что это кажется очевидным выигрышем. Но это противоречит неправильному пониманию стоимости; Подобная функция влияет на спецификацию языка, реализацию, JCK и все учебники по IDE и Java. Нет тривиальных языковых функций. И выгода, хотя и отличная от нуля, довольно мала.

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

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

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

Вместо того чтобы писать

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

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

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

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

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

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

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

Забавно, я наткнулся на этот вопрос.

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

Эли (пост чуть выше) правильно понял суть:

||

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

Итак, представьте, что произойдет, если b == true;

b ||= somethingreturningboolean(); // !!??

это не вызовет somethingreturningaboolean(), если b == true.

Это поведение более очевидно в длинной форме:

б = б || что-то, возвращающее логическое значение();

Вот почему операторы ||= и &&= не существуют. Объяснение должно быть таким: Операторы ||= и &&= не существуют, так как их семантику легко понять неправильно; если вы считаете, что они вам нужны, используйте вместо этого оператор if.

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

&

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

&&

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

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

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

Это разрешено в Ruby.

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

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

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

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