Как правильно сравнивать строки в Java
Что проверяют
Различаете ли вы сравнение ссылок и содержимого и понимаете ли, как работает пул строк. Типичное продолжение: «что выведет "a" + "b" == "ab", а что x + "b" == "ab", если x обычная переменная».
Как отвечать
==: сравнивает ссылки. Литералы интернируются, и одинаковые литералы указывают на один объект. Выражение из констант времени компиляции компилятор склеивает заранее, поэтому"a" + "b" == "ab"даётtrue. Конкатенация с обычной переменной происходит в рантайме и создаёт новый объект:false. Еслиxобъявлена какfinal String x = "a", она снова константа, и результатtrue;equals(): сравнивает содержимое с учётом регистра. ОтnullзащищаютObjects.equals(a, b)или вызов у литерала:"yes".equals(input);equalsIgnoreCase(): посимвольное сравнение без учёта регистра, от локали не зависит. А вотtoLowerCase()без аргумента зависит: в турецкой локали"TITLE".toLowerCase()даст строку с безточечнойı, поэтому для технических строк пишутtoLowerCase(Locale.ROOT);compareTo(): порядок по кодам символов UTF-16, заглавные латинские идут раньше строчных. Для сортировки, которую увидит человек, берутCollator.getInstance(locale), без учёта регистра естьString.CASE_INSENSITIVE_ORDER;contentEquals(): сравнение соStringBuilderили любойCharSequenceбез лишнегоtoString().
Про intern(): он возвращает каноническую ссылку из пула, который с Java 7 лежит в куче. Как способ сравнивать через == это плохая идея, а для экономии памяти на дублях есть дедупликация строк в G1 (-XX:+UseStringDeduplication).
Можно добавить про Unicode: визуально одинаковые строки бывают разными последовательностями кодов, их выравнивает java.text.Normalizer.
Где спотыкаются
Говорят «для литералов == работает, значит можно». Первая же строка из запроса или базы сломает такое сравнение.
Вызывают input.equals("yes"), когда input может быть null, и ловят NullPointerException.
Советуют intern() для всех строк ради скорости. Пул не бесплатный, а выигрыш от сравнения ссылок почти всегда съедается ценой самого интернирования.