Подтвердить что ты не робот

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

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

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, a никогда не может быть равно строковой литературе "что-то". Компилятор должен понять это и, по крайней мере, предупредить меня, что я идиот, который кодирует путь до поздней ночи.

Разъяснение Этот вопрос заключается не в сравнении двух переменных объекта String, а в сравнении строковой переменной String с литералом String. Я понимаю, что следующий код полезен и приведет к различным результатам, чем .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, нет ничего полезного, что я мог бы сделать с этим знанием, не так ли? Если бы я сравнивал две переменные, то да, эта информация была бы полезна, но с переменной и литералом это было бы бессмысленно.

4b9b3361

Ответ 1

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

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

Ответ 2

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

Заметки Java о интерновке строк

Ответ 3

Потому что:

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

Чтобы прояснить, в приведенном примере expersion всегда TRUE, а a может быть == и equals() для литерала String, а в приведенном примере всегда == и equals().

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

Ответ 8

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

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

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

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

Ответ 9

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