Почему 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. & Амп; оператор всегда оценивает оба выражения. & Амп; & оператор оценивает второе выражение только в том случае, если первое выражение истинно.
Наличие оператора & = присваивания действительно не добавит новых функций для языка. Арифметика поразрядного оператора гораздо более выразительна, вы можете выполнять целочисленную поразрядную арифметику, которая включает в себя логическую арифметику. Логические операторы могут просто выполнять булевую арифметику.