Почему Java не предупреждает о == “что-то”?

Это могло бы звучать глупым, но почему не делает компилятора Java, предупреждают о выражении в следующем если оператор:

String a = "something";
if(a == "something"){
  System.out.println("a is equal to something");
}else{
  System.out.println("a is not equal to something");
}

Я понимаю, почему выражение неверно, но AFAIK, банка никогда не быть равным Строковому литералу "что-то". Компилятор должен понять это и по крайней мере предупредить меня, что я - идиот, который кодирует путь к поздно вечером.

Разъяснение, которое Этот вопрос не о сравнении двух Строковых переменных объекта, это о сравнении Строковой переменной объекта к Строковому литералу. Я понимаю, что следующий код полезен и привел бы к различным результатам, чем .equals():

String a = iReturnAString();
String b = iReturnADifferentString();
if(a == b){
  System.out.println("a is equal to b");
}else{
  System.out.println("a is not equal to b");
}

В этом случае a и b мог бы на самом деле указать на ту же область в памяти, даже если это не из-за интернирования. В первом примере, хотя, единственная причина это было бы верно, то, если Java делает что-то негласно, которое не полезно для меня, и которое я не могу использовать для своего преимущества.

Развейте вопрос, Даже если a и строковый литерал обе точки к той же области в памяти, как это полезно для меня в выражении как то выше. Если то выражение возвращает true, нет действительно ничего полезного, которое я мог бы сделать с тем знанием, есть ли? Если бы я сравнивал две переменные, то да, та информация была бы полезна, но с переменной и литералом это довольно бессмысленно.

12
задан Marius 14 May 2010 в 19:17
поделиться

9 ответов

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

Я считаю, что все Checkstyle , FindBugs и PMD будут предупреждать об этом, и, возможно, многие другие плохие практики, которые мы склонны использовать в полусне. или иным образом выведен из строя;).

8
ответ дан 2 December 2019 в 04:42
поделиться

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

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

Следовательно, нет попытки сделать это автоматически.

Если вы думаете о таких вещах, как кеширование, то есть ситуации, в которых вы захотите провести этот тест.

3
ответ дан 2 December 2019 в 04:42
поделиться

"Я понимаю, почему выражение неверно, но AFAIK, a никогда не может быть равно строковому литералу "something"."

Чтобы уточнить, в приведенном примере выражение всегда TRUE и a может быть == и равно() строковому литералу, а в приведенном примере оно всегда == и равно().

Иронично, что вы, похоже, привели редкий контрпример на свой собственный аргумент.

1
ответ дан 2 December 2019 в 04:42
поделиться

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

Java notes about string interning

13
ответ дан 2 December 2019 в 04:42
поделиться

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

0
ответ дан 2 December 2019 в 04:42
поделиться

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

2
ответ дан 2 December 2019 в 04:42
поделиться

Потому что:

  • вы действительно можете использовать == , если работаете с константами и интернировано strings
  • компилятор должен делать исключение только для String и ни для каких других типов. Я имею в виду - всякий раз, когда компилятор встречает == , он должен проверить, являются ли операнды строками , чтобы выдать предупреждение. Что, если аргументами являются Строки , но они упоминаются как Объект или CharSequence ?

Обоснование checkstyle для выдачи ошибка в том, что так часто делают начинающие программисты. А если вы новичок, мне будет сложно настроить checkstyle (или pmd) или даже узнать о них.

Другое дело - реальный сценарий, когда сравниваются строки и в качестве одного из операндов используется литерал. Во-первых, лучше использовать константу ( static final ) вместо литерала. А откуда бы взялся другой операнд? Вполне вероятно, что он будет происходить из той же константы / литерала, где-то еще в коде. Итак, == будет работать.

4
ответ дан 2 December 2019 в 04:42
поделиться

Бывают случаи, когда вам действительно важно, имеете ли вы дело с абсолютно одинаковым объектом, а не с тем, равны ли два объекта. В таких случаях вам нужен ==, а не equals(). У компилятора нет возможности узнать, действительно ли вы хотите сравнить ссылки на равенство или объекты, на которые они указывают.

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

Кроме того, поскольку строки неизменяемы, JVM может сделать так, чтобы строки, которые были бы равны по equals(), использовали один и тот же экземпляр (для экономии памяти), и в этом случае они также будут равны по ==. Таким образом, в зависимости от того, что делает JVM, == вполне может вернуть true. И пример, который вы привели, на самом деле один из тех, где есть приличная вероятность этого, потому что они оба строковые литералы, так что JVM будет довольно легко сделать их одной и той же строкой, и она, вероятно, так и сделает. И, конечно, если вы хотите посмотреть, делает ли JVM две строки одним и тем же экземпляром, вы должны использовать ==, а не equals(), так что есть законная причина использовать == для строк.

Таким образом, компилятор не имеет возможности узнать достаточно о том, что вы делаете, чтобы понять, что использование == вместо equals() должно быть ошибкой. Это может привести к ошибкам, если вы не будете осторожны (особенно если вы привыкли к языку вроде C++, который перегружает == вместо того, чтобы иметь отдельную функцию equals()), но компилятор может сделать за вас лишь очень многое. Существуют законные причины для использования == вместо equals(), поэтому компилятор не будет отмечать это как ошибку.

0
ответ дан 2 December 2019 в 04:42
поделиться

Компилятору все равно, что вы пытаетесь сравнить идентичность с литералом. Можно также возразить, что работа няни кода - не задача компилятора. Поищите инструмент, похожий на ворс, если вы хотите отловить подобные ситуации.

1
ответ дан 2 December 2019 в 04:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: