Это могло бы звучать глупым, но почему не делает компилятора 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, нет действительно ничего полезного, которое я мог бы сделать с тем знанием, есть ли? Если бы я сравнивал две переменные, то да, та информация была бы полезна, но с переменной и литералом это довольно бессмысленно.
Предупреждения компилятора обычно касаются вещей, которые либо явно неверны (условия, которые никогда не могут быть истинными или ложными), либо небезопасны (неконтролируемые приведения). Использование == допустимо, а в некоторых редких случаях преднамеренно.
Я считаю, что все Checkstyle , FindBugs и PMD будут предупреждать об этом, и, возможно, многие другие плохие практики, которые мы склонны использовать в полусне. или иным образом выведен из строя;).
В зависимости от контекста, как сравнения идентичности, так и сравнения значений могут быть допустимыми.
Я могу придумать очень мало запросов, в которых есть детерминированный автоматический алгоритм, позволяющий однозначно определить, что один из них является ошибкой.
Следовательно, нет попытки сделать это автоматически.
Если вы думаете о таких вещах, как кеширование, то есть ситуации, в которых вы захотите провести этот тест.
"Я понимаю, почему выражение неверно, но AFAIK, a никогда не может быть равно строковому литералу "something"."
Чтобы уточнить, в приведенном примере выражение всегда TRUE и a может быть == и равно() строковому литералу, а в приведенном примере оно всегда == и равно().
Иронично, что вы, похоже, привели редкий контрпример на свой собственный аргумент.
На самом деле они действительно могут быть одной и той же ссылкой, если Java решит интернировать строку. Интернализация строк - это понятие о наличии только одного значения для отдельной строки во время выполнения.
Java notes about string interning
Существуют инструменты, которые будут предупреждать вас об этих конструкциях; не стесняйтесь их использовать. Однако есть допустимые случаи, когда вы хотите использовать == в строках, и гораздо хуже языковой дизайн предупредить пользователя о совершенно допустимой конструкции, чем не предупредить его. Когда вы используете Java около года (и я готов поспорить, что вы еще не достигли этой стадии), вы обнаружите, что избегание подобных конструкций - вторая натура.
На самом деле, иногда это может быть правдой, в зависимости от того, берет ли Java существующую строку из своего внутреннего кеша строк, создавая первое объявление и затем сохраняя его, или принимает его для обоих объявлений строк.
Потому что:
==
, если работаете с константами и интернировано strings String
и ни для каких других типов. Я имею в виду - всякий раз, когда компилятор встречает ==
, он должен проверить, являются ли операнды строками
, чтобы выдать предупреждение. Что, если аргументами являются Строки
, но они упоминаются как Объект
или CharSequence
? Обоснование checkstyle для выдачи ошибка в том, что так часто делают начинающие программисты. А если вы новичок, мне будет сложно настроить checkstyle (или pmd) или даже узнать о них.
Другое дело - реальный сценарий, когда сравниваются строки и в качестве одного из операндов используется литерал. Во-первых, лучше использовать константу ( static final
) вместо литерала. А откуда бы взялся другой операнд? Вполне вероятно, что он будет происходить из той же константы / литерала, где-то еще в коде. Итак, ==
будет работать.
Бывают случаи, когда вам действительно важно, имеете ли вы дело с абсолютно одинаковым объектом, а не с тем, равны ли два объекта. В таких случаях вам нужен ==
, а не equals()
. У компилятора нет возможности узнать, действительно ли вы хотите сравнить ссылки на равенство или объекты, на которые они указывают.
Теперь, гораздо менее вероятно, что вы захотите ==
для строк, чем для пользовательского типа, но это не гарантирует, что вы не захотите этого, и даже если бы захотели, это означает, что компилятор должен будет специально проверять строки, чтобы убедиться, что вы не использовали ==
для них.
Кроме того, поскольку строки неизменяемы, JVM может сделать так, чтобы строки, которые были бы равны по equals()
, использовали один и тот же экземпляр (для экономии памяти), и в этом случае они также будут равны по ==
. Таким образом, в зависимости от того, что делает JVM, ==
вполне может вернуть true. И пример, который вы привели, на самом деле один из тех, где есть приличная вероятность этого, потому что они оба строковые литералы, так что JVM будет довольно легко сделать их одной и той же строкой, и она, вероятно, так и сделает. И, конечно, если вы хотите посмотреть, делает ли JVM две строки одним и тем же экземпляром, вы должны использовать ==
, а не equals()
, так что есть законная причина использовать ==
для строк.
Таким образом, компилятор не имеет возможности узнать достаточно о том, что вы делаете, чтобы понять, что использование ==
вместо equals()
должно быть ошибкой. Это может привести к ошибкам, если вы не будете осторожны (особенно если вы привыкли к языку вроде C++, который перегружает ==
вместо того, чтобы иметь отдельную функцию equals()
), но компилятор может сделать за вас лишь очень многое. Существуют законные причины для использования ==
вместо equals()
, поэтому компилятор не будет отмечать это как ошибку.
Компилятору все равно, что вы пытаетесь сравнить идентичность с литералом. Можно также возразить, что работа няни кода - не задача компилятора. Поищите инструмент, похожий на ворс, если вы хотите отловить подобные ситуации.