Сравнение строки с пустой строкой (Java)

У меня вопрос о сравнении строки с пустой строкой в ​​Java. Есть ли разница, если я сравниваю строку с пустой строкой с == или equals ? Например:

 String s1 = "hi"; if (s1 == "") 

или

 if (s1.equals("")) 

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

 s1 == "" 

не является надежным, поскольку он проверяет ссылочное равенство, а не равенство объектов (а String не является строго каноническим).

 s1.equals("") 

лучше, но может страдать от ненужных указателей. Еще лучше:

 "".equals(s1) 

Исключение исключений нулевого указателя.

EDIT: Хорошо, вопрос был задан о канонической форме . Эта статья определяет это как:

Предположим, что мы имеем некоторое множество S объектов с отношением эквивалентности. Каноническая форма дается путем обозначения некоторых объектов S как «в канонической форме», так что каждый рассматриваемый объект эквивалентен точно одному объекту в канонической форме.

Чтобы дать вам практический пример: взять набор рациональных чисел (или «фракций», которые обычно называются). Рациональное число состоит из числителя и знаменателя (делителя), оба из которых являются целыми числами. Эти рациональные числа эквивалентны:

3/2, 6/4, 24/16

Rational nubmers обычно пишутся так, что gcd (наибольший общий делитель) равен 1. Таким образом, все они будут упрощены до 3/2. 3/2 можно рассматривать как каноническую форму этого множества рациональных чисел.

Итак, что это значит при программировании, когда используется термин «каноническая форма»? Это может означать пару вещей. Возьмем, к примеру, этот воображаемый class:

 public class MyInt { private final int number; public MyInt(int number) { this.number = number; } public int hashCode() { return number; } } 

Хэш-код classа MyInt является канонической формой этого classа, потому что для множества всех экземпляров MyInt вы можете взять любые два элемента m1 и m2, и они будут подчиняться следующему соотношению:

 m1.equals(m2) == (m1.hashCode() == m2.hashCode()) 

Это отношение является сущностью канонической формы. Более распространенный способ получения этого урожая заключается в том, что вы используете фабричные методы для classов, таких как:

 public class MyClass { private MyClass() { } public MyClass getInstance(...) { ... } } 

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

  • Всегда возвращайте один и тот же экземпляр (абстрагированный синглтон);
  • Просто создайте новое взаимодействие с каждым вызовом;
  • Возвращать объекты в канонической форме (подробнее об этом в секунду); или
  • как хочешь.

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

То, что вы можете сделать с этим заводским методом, – это кешировать созданные вами экземпляры, так что для любых двух экземпляров s1 и s2 они подчиняются следующему тесту:

 (s1 == s2) == s1.equals(s2) 

Поэтому, когда я говорю, что String не является строго каноническим, это означает, что:

 String s1 = "blah"; String s2 = "blah"; System.out.println(s1 == s2); // true 

Но по мере того, как другие выкалывают, вы можете изменить это, используя:

 String s3 = new String("blah"); 

и возможно:

 String s4 = String.intern("blah"); 

Таким образом, вы не можете полностью полагаться на ссылочное равенство, чтобы не полагаться на него вообще.

В качестве предостережения к описанному выше шаблону я должен указать, что управление созданием объекта с помощью частных конструкторов и фабричных методов не гарантирует, что эталонное равенство означает равенство объектов из-за сериализации. Сериализация отключает механизм создания обычного объекта. Джош Блох рассказывает об этой теме в «Эффективной Java» (первоначально в первом выпуске, когда он рассказывал о типовом шаблоне enum, который позже стал языковой функцией в Java 5), ​​и вы можете обойти его, перегружая (private) метод readResolve (). Но это сложно. Классные погрузчики также повлияют на проблему.

Во всяком случае, это каноническая форма.

Это будет зависеть от того, является ли строка литералом или нет. Если вы создаете строку с

 new String("") 

Тогда он никогда не будет соответствовать «» с помощью оператора equals, как показано ниже:

  String one = ""; String two = new String(""); System.out.println("one == \"\": " + (one == "")); System.out.println("one.equals(\"\"): " + one.equals("")); System.out.println("two == \"\": " + (two == "")); System.out.println("two.equals(\"\"): " + two.equals("")); 

 one == "": true one.equals(""): true two == "": false two.equals(""): true 

В принципе, вы хотите всегда использовать equals ()

Это немного в стороне от вашего первоначального вопроса, но всегда есть

 if(s1.length() == 0) 

Я считаю, что это эквивалентно методу isEmpty () из 1.6.

 "".equals(s) 

Кажется, это лучший вариант, но есть также Stringutils.isEmpty(s) содержащиеся в библиотеке Apache commons lang

Короткий ответ

 s1 == "" // No! s1.equals("") // Ok s1.isEmpty() // Ok: fast (from Java 1.6) "".equals(s1) // Ok: null safe 

Я уверен, что s1 не является нулевым и использует isEmpty ().

Примечание: пустая строка “” не является специальной строкой, а считается как любое другое значение.

Немного более длинный ответ

Ссылки на объекты String зависят от способа их создания:

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

 String s1 = new String(""); String s2 = new String(""); s1 == s2 // false 

Строковые объекты, созданные с помощью оператора =, сопровождаемые значением, заключенным в двойные кавычки whitin ( = «значение» ), хранятся в пуле объектов String: перед созданием нового объекта в пуле объект с таким же значением выполняется в пуле и ссылается, если найден.

 String s1 = ""; // "" added to the pool String s2 = ""; // found "" in the pool, s2 will reference the same object of s1 s1 == s2 // true 

То же самое верно для созданных строк, содержащих значение whitin double quotes (“value”), поэтому:

 String s1 = ""; s1 == ""; //true 

String равно методам проверки для обоих, поэтому безопасно писать:

 s1.equals(""); 

Это выражение может вызывать исключение NullPointerException, если s1 == null, поэтому, если вы не проверяете значение null раньше, безопаснее писать:

 "".equals(s1); 

Пожалуйста, прочитайте также. Как сравнить строки в Java?

Надеюсь, что это может помочь не столь опытным пользователям, которые могут найти другие ответы слишком сложно. 🙂

Строка, является строкой, является строкой, является ли она пустой строкой или нет. Используйте equals() .

Используйте String.isEmpty () или StringUtils.isEmpty (String str), если вам нужна нулевая проверка.

Учитывая две строки:

 String s1 = "abc"; String s2 = "abc"; 

-или –

 String s1 = new String("abc"); String s2 = new String("abc"); 

Оператор ==, выполняемый на двух объектах, проверяет идентичность объекта (он возвращает true, если два оператора возвращаются к одному экземпляру объекта.) Фактическое поведение ==, примененное к java.lang.Strings, не всегда представляется последовательным из-за Штрих-интернирование.

В Java строки интернированы (по крайней мере, частично по усмотрению JVM.) В любой момент времени s1 и s2 могут быть или не быть интернированными, чтобы быть одной и той же ссылкой на объект (если они имеют одинаковое значение). Таким образом, s1 == s2 может или не может возвращать true, основываясь исключительно на том, были ли интернированы s1 и s2.

Создание s1 и s2, равное пустым Строкам, не влияет на это – они все еще могут быть или не быть интернированы.

Короче говоря, == может или не может возвращать true, если s1 и s2 имеют одинаковое содержимое. s1.equals (s2) гарантированно возвращает true, если s1 и s2 имеют одинаковое содержимое.

  • Строка неизменна. В чем же смысл?
  • Сравнить номера версий без использования функции split
  • Поиск строки Java, игнорирующий акценты
  • Самый эффективный способ конкатенации строк?
  • Алгоритм поиска нескольких совпадений строк
  • Как преобразовать String в ArrayList?
  • Выключение строки C ++
  • Обращение строки в C
  • В C # следует ли использовать string.Empty или String.Empty или "" для инициализации строки?
  • Почему class String объявлен окончательным в Java?
  • Пакетный файл для удаления первых трех строк текстового файла
  • Давайте будем гением компьютера.