Основы Java: понимание равенства строк

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

Использование метода equals()

Класс String содержит метод equals(), который используется для определения того, являются ли две строки одинаковыми. Он возвращает логическое значение.

Давайте посмотрим на код, использующий этот метод:

Object obj = new Object();      
String test1 = obj.toString(); 
String test2 = obj.toString(); System.out.println(test1.equals(test2)); // true

Иногда мы можем не заботиться о чувствительности к регистру. В этой ситуации мы можем использовать метод equalsIgnoreCase():

String name1 = "Amir"; 
String name2 = "aMiR"; System.out.println(name1.equalsIgnoreCase(name2)); // true

Как избежать исключений с помощью equals()

Сравнивая строковую переменную с литералом, мы можем записать ее несколькими способами:

String name = "Amir"; 
System.out.println(name.equals("Amir")); // true System.out.println("Amir".equals(name)); // true

Обратите внимание на строку 3, как мы поменяли местами порядок строкового литерала и переменной. Это законный и на самом деле предпочтительный подход по сравнению со строкой 2.

Почему?

Потому что он не выдаст NullPointerException, если наша переменная имени окажется нулевой. Он просто вернет false, что обычно нам и нужно.

Давайте взглянем на код, демонстрирующий этот факт:

String name = null; 
System.out.println("Amir".equals(name)); // false System.out.println(name.equals("Amir")); // NullPointerException

Почему бы не использовать оператор ==?

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

Когда операнды являются объектами, оператор == сравнивает их ссылки или то, где они хранятся в памяти. Он не проверяет значение, хранящееся в этих объектах.

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

Object obj = new Object();      
String test1 = obj.toString(); 
String test2 = obj.toString();
 
System.out.println(test1 == test2); // false

Обратите внимание, что мы присвоили обеим строкам одно и то же значение, но наша проверка на равенство по-прежнему возвращала false.

Оператор проверяет, являются ли они тем же объектом в памяти, которым они не являются.

Предупреждение о строковых литералах

Смущает то, как ведет себя Java, когда оператор == используется для строковых литералов.

String name1 = "Amir"; 
String name2 = "Amir"; 
System.out.println(name1 == name2); // true

Оператор на самом деле ведет себя так, как ожидалось, и возвращает true!

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

Итак, в примере кода обе переменные фактически указывают на один и тот же объект в памяти.

Вывод

Всегда используйте методы equals() или equalsIgnoreCase() для равенства строк в Java. Это уменьшит вероятность создания в коде незаметных ошибок, которые трудно обнаружить.

Первоначально опубликовано на www.codebyamir.com 20 февраля 2018 г.