Вопрос-ответ

How do I compare strings in Java?

Как мне сравнить строки в Java?

До сих пор я использовал оператор == в своей программе для сравнения всех моих строк. Однако я столкнулся с ошибкой, заменил одну из них на .equals() вместо этого, и это исправило ошибку.

Это == плохо? Когда это следует и не следует использовать? В чем разница?

Переведено автоматически
Ответ 1

== проверяет равенство ссылок (являются ли они одним и тем же объектом).

.equals() проверяет равенство значений (содержат ли они одни и те же данные).

Objects.equals() проверяет null перед вызовом.equals(), поэтому вам не нужно этого делать (доступно начиная с JDK7, также доступно в Guava).

Следовательно, если вы хотите проверить, имеют ли две строки одинаковое значение, вы, вероятно, захотите использовать Objects.equals().

// These two have the same value
new String("test").equals("test") // --> true

// ... but they are not the same object
new String("test") == "test" // --> false

// ... neither are these
new String("test") == new String("test") // --> false

// ... but these are because literals are interned by
// the compiler and thus refer to the same object
"test" == "test" // --> true

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

Из спецификации языка Java JLS 15.21.3. Ссылаются на операторы равенства == и !=:


Хотя == может использоваться для сравнения ссылок типа String, такой тест на равенство определяет, относятся ли два операнда к одному и тому же String объекту. Результатом будет, false если операнды являются разными String объектами, даже если они содержат одну и ту же последовательность символов (§ 3.10.5, §3.10.6). Содержимое двух строк s и t может быть проверено на равенство с помощью вызова метода s.equals(t).


Вы почти всегда хотите использовать Objects.equals(). В редкой ситуации, когда вы знаете, что имеете дело с интернированными строками, вы можете использовать ==.

Из JLS 3.10.5. Строковые литералы:


Более того, строковый литерал всегда ссылается на один и тот же экземпляр класса String. Это связано с тем, что строковые литералы - или, в более общем смысле, строки, являющиеся значениями постоянных выражений (§ 15.28) - "интернированы", чтобы совместно использовать уникальные экземпляры с использованием метода String.intern.


Похожие примеры также можно найти в JLS 3.10.5-1.

Другие методы, которые следует рассмотреть

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

String.contentEquals() сравнивает содержимое String с содержимым любого CharSequence (доступно начиная с Java 1.5). Избавляет вас от необходимости превращать ваш StringBuffer и т.д. В строку перед выполнением сравнения на равенство, но оставляет вам проверку null.

Ответ 2

== проверяет ссылки на объекты, .equals() проверяет строковые значения.

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

Например:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

Но остерегайтесь нулей!

== отлично обрабатывает null строки, но вызов .equals() из нулевой строки вызовет исключение:

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

Итак, если вы знаете, что fooString1 может быть null, сообщите об этом читателю, написав

System.out.print(fooString1 != null && fooString1.equals("bar"));

Следующие строки короче, но менее очевидно, что они проверяют наличие null:

System.out.print("bar".equals(fooString1));  // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar")); // Java 7 required
Ответ 3

== сравнивает ссылки на объекты.

.equals() сравнивает строковые значения.

Иногда == создается иллюзия сравнения строковых значений, как в следующих случаях:

String a="Test";
String b="Test";
if(a==b) ===> true

Это связано с тем, что при создании любого строкового литерала JVM сначала выполняет поиск этого литерала в пуле строк, и если находит совпадение, та же ссылка будет дана на новую строку. Из-за этого мы получаем:

(a ==b) ===> true

                       String Pool
b -----------------> "test" <-----------------a

Однако, == сбой в следующем случае:

String a="test";
String b=new String("test");
if (a==b) ===> false

В этом случае для new String("test") инструкции в куче будет создана новая строка, и на нее будет дана ссылка b, поэтому b ссылка будет дана в куче, а не в пуле строк.

Теперь a указывает на строку в пуле строк, в то время как b указывает на строку в куче. Из-за этого мы получаем:

if(a==b) ===> false.

                String Pool
"test" <-------------------- a

Heap
"test" <-------------------- b

В то время как .equals() всегда сравнивает значение String, чтобы оно давало true в обоих случаях:

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

Поэтому использование .equals() всегда лучше.

Ответ 4

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

Метод .equals() проверит, имеют ли две строки одинаковое значение.

java string