Путать с == и = в инструкции if

Я знаю, что мы не можем использовать оператор присваивания в операторах if в java, как мы используем в любых других языках.

это

            int a;

            if(a = 1) {  } 

выдаст ошибку компиляции.

но как следующий код работает нормально?

           boolean b;

           if(b = true) {   }

РЕДАКТИРОВАТЬ: это исключение из правила, что назначение не может использоваться в операторе if.


person GuruKulki    schedule 06.03.2010    source источник
comment
Неплохая идея - выработать привычку ставить константу первой в ваших операторах if .... То есть: if (true == b) {} и if (1 == a) {} Эта привычка гарантирует, что компилятор ударит вас, если вы напишете = вместо ==.   -  person O. Jones    schedule 07.03.2010
comment
@Ollie: мнения по этому поводу сильно расходятся. Что касается удобочитаемости, это плохая идея. Более того, он не дает никаких преимуществ для таких языков, как Java, поскольку здесь не может возникнуть путаницы. Я имею в виду, никто никогда не пишет тест как if (a == true), верно?   -  person Konrad Rudolph    schedule 07.03.2010
comment
@Konrad. Вы правы в Java, но эта переработанная модель C, которая работает на PERL и некоторых других языках, спасла меня много раз.   -  person O. Jones    schedule 11.03.2010
comment
Не работает во многих случаях, например if ( $a == $b ). Ужасно читать, никто не говорит «5 - это». ИМО, проще просто быть внимательнее при написании if условий.   -  person rjh    schedule 06.04.2010
comment
В наши дни большинство компиляторов @Ollie имеют возможность предупреждать вас, если вы напишете if(foo = x) или что-то в этом роде.   -  person Spudd86    schedule 18.06.2010


Ответы (5)


Потому что «результат» присваивания - это присвоенное значение ... так что это все еще выражение boolean во втором случае. if выражения требуют, чтобы условие было boolean выражением, которому удовлетворяет второе, но не первое. Фактически, ваши два фрагмента:

int a;

a = 1;
if (a) { }

и

boolean b;

b = true;
if (b) { }

Ясно ли из этого расширения, что вторая версия будет компилироваться, но не первая?

Это одна из причин, по которой не следует напрямую сравнивать истину и ложь. Поэтому я всегда просто писал if (b) вместо if (b == true) и if (!b) вместо if (b == false). У вас все еще возникают проблемы с if (b == c), когда b и c являются boolean переменными, по общему признанию - опечатка может вызвать проблему. Я не могу сказать, что со мной такое когда-либо случалось.

РЕДАКТИРОВАТЬ: ответ на ваше редактирование - назначения всех видов могут использоваться в if операторах - и while циклах и т. Д., Если общее выражение условия равно boolean. Например, у вас может быть:

String line;
while ((line = reader.readLine()) != null)
{
    // Do something with a line
}

Хотя я обычно избегаю побочных эффектов в условиях, эта конкретная идиома часто полезна для примера, показанного выше, или для использования InputStream.read. В основном это «пока значение, которое я прочитал, полезно, используйте его».

person Jon Skeet    schedule 06.03.2010
comment
Вы уверены, что в последнем примере есть лишняя пара круглых скобок? Я думал, что назначение имеет последний приоритет в Java ... - person user85421; 07.03.2010
comment
@ Карлос: Хороший улов. Может, я так привык к тому, чтобы нарочно его вставлять, что никогда не пробовал без этого :) - person Jon Skeet; 07.03.2010
comment
Я обычно думаю об этой идиоме (и использую ее, когда подходит аналогия) в терминах методов hasNext и next итератора - он в основном реализует их комбинацию для чего-то, что явно не является итератором (и я очень хочу, чтобы у читателей была реализация этот интерфейс добавлен в более поздних версиях). - person Carl; 07.03.2010
comment
Кроме того, в некоторых языках (C, C ++) логическое значение может быть заменено целым числом, при этом 0 означает ложь, а не 0 - истину. Что значительно увеличивает шансы на ошибку = / ==. - person mtruesdell; 07.03.2010
comment
@mtruesdell: Действительно, хотя я считаю, что большинство компиляторов C и C ++ будут предупреждать вас, если у вас нет дополнительной пары круглых скобок, чтобы подчеркнуть, что это сделано намеренно ... по крайней мере, если у вас есть предупреждения, которые поднялись достаточно высоко. - person Jon Skeet; 07.03.2010
comment
Вы можете избежать опасности if (b == c), используя вместо этого что-то вроде if (! (B ^ c)). - person ILMTitan; 08.03.2010
comment
@ILMTitan: Да, но если вы думаете достаточно об этом, чтобы написать это, скорее всего, вы все равно поймете это правильно :) - person Jon Skeet; 08.03.2010

Для if вам нужно выражение, которое оценивается как логическое. b = true оценивается как логическое, но a = 1 оценивается как int, поскольку присваивания всегда оценивают присвоенные значения.

person Gumbo    schedule 06.03.2010

Причина, по которой второй код работает нормально, заключается в том, что он присваивает 'b' значение true, а затем сравнивает, чтобы увидеть, истинно ли b или ложно. Причина, по которой вы можете это сделать, заключается в том, что вы можете выполнять операторы присваивания внутри оператора if, И вы можете сравнивать с логическим значением само по себе. Это будет то же самое, что и if (true).

person JasCav    schedule 06.03.2010

В java у вас нет неявного приведения типов. Значит, не-логические значения или не преобразовываются автоматически в логические.

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

person Ikke    schedule 06.03.2010

Правило не в том, что «назначение не может использоваться в операторе if», а в том, что «условие в операторе if должно иметь тип boolean». Выражение присваивания производит значение присваиваемого типа, поэтому Java разрешает присваивание только в операторе if, если вы присваиваете значение boolean.

Это веская причина, по которой следует избегать стиля if (foo == true) и вместо этого просто писать if (foo).

person Greg Hewgill    schedule 06.03.2010