Почему в Java нет String.Empty?

260

Я понимаю, что каждый раз, когда я набираю строковый литерал "" , в пуле строк указывается один и тот же объект String.

Но почему String API не включает public static final String Empty = "";, чтобы я мог использовать ссылки на String.Empty?

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

Так что за String.Empty не было Grand Design Reason, или создатели языка просто не разделяли мои взгляды?

Том Тресанский
источник
5
Aidanc: Я думаю , что он имел в виду ситуации , когда вы делаете такие вещи , как outputBlah = ""и он , вероятно , предпочитает something == String.Emptyболее , something.Length > 0а также (пропустить проверку нулевой.)
Skurmedel
2
@Aidanc - он искал «пустой элемент», такой как Collections.EMPTY_SET , а не функцию для проверки строки «пустота».
Тим Стоун
2
@Aidanc: На самом деле это вдохновило 'TextBox.setText (""); ".
Том Тресанский
3
Там есть String.isEmpty()функция ... почему вы хотите String.EMPTY?
Бухаке Синди
8
String.isEmpty()не возвращает пустую строку.
Стив Куо

Ответы:

191

String.EMPTY12 символов и ""два, и они оба будут ссылаться на один и тот же экземпляр в памяти во время выполнения. Я не совсем уверен, зачем String.EMPTYэкономить время компиляции, на самом деле я думаю, что это будет последним.

Особенно с учетом того, что Strings являются неизменяемыми, это не значит, что вы можете сначала получить пустую строку и выполнить с ней некоторые операции - лучше всего использовать StringBuilder(или StringBufferесли вы хотите быть потокобезопасным) и превратить это в строку.

Обновление
От вашего комментария к вопросу:

Что вдохновило это на самом деле TextBox.setText("");

Я считаю, что было бы вполне законно предоставить константу в вашем соответствующем классе:

private static final String EMPTY_STRING = "";

А затем ссылаться на это как в вашем коде как

TextBox.setText(EMPTY_STRING);

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

Ноэль М
источник
14
Я все равно +1 тебе, но я чувствую себя грязно, потому что ты упомянул, StringBuilderне говоря о том, что в девяти из десяти случаев совершенно неуместно использовать, StringBuilderа не объединять.
Рандольфо
85
Я предпочитаю использовать string.empty, в основном потому, что он более явный. Кроме того, существуют ситуации с оценками, в которых может быть сложнее визуально различить «» и такие вещи, как «». В конце концов, как отмечают другие, это лишь одна из тех бессмысленных стилевых вещей, которые дают нам пищу для споров, когда нам надоедает настоящая работа. =)
JohnFx
@Nodel M: Что касается времени компиляции, я бы предположил, что если есть 2 строковых литерала, определенных в 2 разных исходных файлах с одинаковым строковым значением, когда компилятор достигает 2-го, ему нужно выполнить какую-то проверку для выяснения " эй, я уже знаю об этой строке отсюда ". По общему признанию, я не эксперт в Java-компиляторе, но как это НЕ может иметь место? И я думаю, что пропуск этой проверки приведет к незначительному улучшению времени компиляции.
Том Тресанский
@Tom - Я полагаю, что интернирование String выполняется во время выполнения, а не во время компиляции, поэтому на самом деле, если у вас есть пустая строка в качестве константы в другом файле, компилятор должен ссылаться на этот класс для разрешения в литерал String.
Ноэль М
1
@Randolpho При использовании конкатенации строк вы фактически используете StringBuilder под капотом.
вискисьерра
133

использование org.apache.commons.lang.StringUtils.EMPTY

нефрит
источник
30
Выглядит намного приятнее и легче для чтения, чем пустая "". Я надеюсь, что это не только я.
Лакатос Дьюла
2
@LakatosGyula - я думаю, что это может быть (только вы). Опытные Java-программисты не испытывают проблем с чтением ""... и большинство из них, вероятно, будут громко возражать против использования, за EMPTYисключением особых ситуаций, где EMPTYимеет значение, специфичное для домена. (И в таких случаях, возможно, есть более подходящее имя.)
Стивен С.
14
@LakatosGyula Это не только ты. Я перешел с Java на разработку .NET, и String.Empty был функцией, которую мне было приятно найти в рамках. Мне нравится явная природа этого над пустым набором цитат.
yohohoho
64
@StephenC Когда я вижу пустое "", первое, что приходит мне в голову, это ошибка, кто-то не завершил функцию и т. Д. С помощью String.EMPTY я точно знаю, что разработчик намеревался вернуть пустую строку.
Лакатос Дьюла
1
Также полезно для тех случаев, когда линтер говорит: «используйте именованную константу вместо бла-бла-бла». Каждый программист знает, что "" не волшебство, но лучше не объяснять это клиенту.
ЛизХ
28

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

if ("".equals(text))

В конечном счете, вы должны делать то, что считаете верным. Большинство программистов предполагают, что "" означает пустую строку, а не строку, в которую кто-то что-то забыл положить.

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

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

Питер Лори
источник
1
Я опоздал на вечеринку, но, поскольку строки Java неизменны, я считаю, что все пустые строки в JVM - это просто разные ссылки на один и тот же объект String. Так что просто следующее также правильно: if ("" == text)
Наслаждайся Бхатия
12
@AjoyBhatia Проблема в том, что вы можете создавать новые пустые строки. if ("" == new String())ложно Лучший тестif(text.isEmpty())
Питер Лори
1
@AjoyBhatia - Только если строки интернированы. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Если вам действительно нужна константа String.EMPTY, вы можете создать в своем проекте статический финальный класс утилиты с именем «Константы» (например). Этот класс будет поддерживать ваши константы, включая пустую строку ...

В той же идее вы можете создавать константы ZERO, ONE int ... которые не существуют в классе Integer, но, как я прокомментировал, было бы трудно писать и читать:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

И т.п.

Бенуа Кортин
источник
8

Apache StringUtils также решает эту проблему.

Недостатки других опций:

  • isEmpty () - небезопасно. Если строка является нулевой, бросает NPE
  • length () == 0 - опять не является нулевым. Также не учитываются пробельные строки.
  • Сравнение с ПУСТОЙ константой - не может быть нулевым. Проблема пробелов

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

Freiheit
источник
3
так ... это , кажется , единственный безопасный вариант ужасного состояние Yoda: "".equals(s)?
Ли Райан
8

Не просто говорите, что «пул памяти строк повторно используется в буквальной форме, регистр закрыт». То, что компиляторы делают под капотом, здесь не главное. Вопрос обоснованный, особенно учитывая количество полученных голосов.

Речь идет о симметрии , без этого API труднее использовать для людей. Ранние Java SDK, как известно, игнорировали это правило, и сейчас уже слишком поздно. Вот несколько примеров на моей голове, не стесняйтесь вставить свой «любимый» пример:

  • BigDecimal.ZERO, но без AbstractCollection.EMPTY, String.EMPTY
  • Array.length но List.size ()
  • List.add (), Set.add () но Map.put (), ByteBuffer.put () и давайте не будем забывать StringBuilder.append (), Stack.push ()
Славомир
источник
Даже если вы назвали длину параметра List (), вам все равно нужна скобка, так как это метод. Array.length является публичной конечной переменной, которая работает только потому, что массивы являются неизменяемыми. Таким образом, у вас все еще будут Array.length и List.length (). Я бы сказал, что это более запутанно и подвержено ошибкам. Что касается .append () и .push (), хотя они и выполняют аналогичные задачи, я думаю, что они названы правильно. Добавление строки - это именно то, что вы делаете, но вы не «добавляете» стек, а толкаете и выталкиваете значения. И StringBuilder.push () подразумевает StringBuilder.pop (), что невозможно.
Крейг Партон
Исходя из шаблонов / обобщений, согласованные интерфейсы также помогают с алгоритмами. Если для алгоритма требуется длина коллекции, мы заботимся о length (T) или T.length (). Точно так же добавление в конец стека, списка или строки может быть сделано универсальным add () или append (). Вы упомянули, что массив в Java является неизменным / встроенным типом с открытым значением длины. Это нормально, это не значит, что компилятор не может обрабатывать или генерировать код для length (T) или T.length (). Котлин генерирует ряд внутренних методов для различных случаев.
Славомир
Но метод с последовательным именем length () позволяет нам только проверять длину. Насколько это полезно? Если ваша цель состоит в том, чтобы абстрагировать списки и массивы, чтобы их можно было каким-либо образом использовать через интерфейс, вам также необходим согласованный способ чтения или записи данных. Теперь вам нужно сгенерировать методы get (), set () и add (). По сути, вы создаете менее функциональное представление списка массива. Поскольку Arrays.asList () доступен, прост в использовании и легок, зачем изобретать велосипед? Массивы, списки, StringBuilders и стеки имеют определенное назначение. Кажется, лучше спроектировать ваш интерфейс так, чтобы он наилучшим образом подходил.
Крейг Партон
5

Все те "" литералы являются одним и тем же объектом. Зачем делать все эти дополнительные сложности? Это просто больше текста и менее понятно (стоимость компилятора минимальна). Поскольку строки Java являются неизменяемыми объектами, их вообще никогда не нужно различать, за исключением, возможно, эффективности, но с пустым строковым литералом это не имеет большого значения.

Если вы действительно хотите EmptyStringпостоянную, сделайте это сами. Но все, что он будет делать, это поощрять еще более подробный код; не будет никогда какой - либо пользы для этого.

Donal Fellows
источник
27
x = String.Emptyпередает намерение лучше, чем x = "". Последнее может быть случайным упущением. Для того, чтобы сказать , что не существует и не какие - либо выгоды неверны.
Джеффри Л Уитледж
@Джеффри: Я не думаю, что я особенно согласен. Это одна из тех вещей, где нет строгого правила, я полагаю.
Donal Fellows
Да, важно отметить, что компилятор java проверяет, существуют ли строковые литералы перед созданием нового экземпляра в пуле строк.
Rds
1
@ Джеффри - зная, что это очень старая и субъективная дискуссия. x = String.Emptyпередает намерение, правда. Но предположим, что язык предоставляет константу String.Empty, когда вы сталкиваетесь, x = ""вы все еще точно знаете о намерении точно так же, как если бы такой константы не было. Вы должны были бы гарантировать, что все места в мире Java-кода, где пустая строка была предназначена, не будут использоваться ""для получения информации, которую вы упоминаете. По иронии судьбы, C # действительно использует константу и поощряет ее использование, поэтому, как я уже сказал, я знаю, что это дискуссия с очень большим мнением.
chiccodoro
@ chiccodoro - Да, это правда. Вот почему пустой строковый литерал ""должен быть недопустимым, чтобы исключить несчастные случаи. Я шучу!
Джеффри Л Уитледж
4

В дополнение к тому, что сказал Ноэль М, вы можете посмотреть на этот вопрос, и этот ответ показывает, что константа используется повторно.

http://forums.java.net/jive/message.jspa?messageID=17122

Строковая константа всегда "интернирована", поэтому такая константа на самом деле не нужна.

String s=""; String t=""; boolean b=s==t; // true
Джеймс Блэк
источник
1
ссылка мертва
Дитер
3

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

или создатели языка просто не разделяют мои взгляды?
Ага. Мне кажется, это вещь с очень низким приоритетом.

Никита Рыбак
источник
6
Там нет такой гарантии ... Ну, JLS заявляет, что так и должно быть.
Тим Стоун
@Tim Нет, если ты не сделаешь вызов 'интерна'. Легко программно построить две одинаковые большие строки и проверить.
Никита Рыбак
@Tim Например, повторите a + = "a"; 100 раз, сделайте то же самое с b и проверьте.
Никита Рыбак
5
Вы правы, но то, что вы описали, не является строковым литералом или выражением, результат которого может быть гарантирован во время компиляции (например, String username = "Bob" + " " + "Smith";). Строки, созданные программно, не имеют гарантий интернирования, если вы явно не вызываете, intern()как вы заявили. Сценарий OP описывает использование пустого строкового литерала ""по всему коду, хотя в этом случае происходит автоматическое интернирование.
Тим Стоун
@Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();Теперь и aи bуказывают на ту же ячейку памяти в PermGen. Смотрите эту статью
1ac0
1

Поздний ответ, но я думаю, что он добавляет что-то новое в эту тему.

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

Константа будет полезна, потому что она предотвратит некоторые ошибки кода, оставшиеся незамеченными.

Скажем, у вас большая база кода с сотнями ссылок на "". Кто-то изменяет один из них при прокрутке кода и меняет его на «». Такое изменение будет иметь высокую вероятность остаться незамеченным в производстве, и в этот момент может возникнуть какая-то проблема, источник которой будет сложно обнаружить.

OTOH, библиотечная константа с именем EMPTY, если подвержена той же ошибке, сгенерирует ошибку компилятора для чего-то вроде EM PTY.

Определение вашей собственной константы все еще лучше. Кто-то может все же изменить его инициализацию по ошибке, но из-за его широкого применения воздействие такой ошибки будет гораздо труднее остаться незамеченным, чем ошибка в одном случае использования.

Это одно из основных преимуществ, которые вы получаете от использования констант вместо литеральных значений. Люди обычно признают, что использование константы для значения, используемого в десятках мест, позволяет легко обновить это значение только в одном месте. Что менее часто признается, так это то, что это также предотвращает случайное изменение этого значения, потому что такое изменение будет проявляться повсюду. Так что да, "" короче, чем EMPTY, но EMPTY безопаснее использовать, чем ""

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

Laurentiu Cristofor
источник
-16

Для тех, кто претендует ""и String.Emptyявляются взаимозаменяемыми или что"" лучше, вы очень не правы.

Каждый раз, когда вы делаете что-то вроде myVariable = ""; вы создаете экземпляр объекта. Если бы Java-объект String имел открытую константу EMPTY, был бы только 1 экземпляр объекта ""

Например: -

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10 (11 включая String.EMPTY) указателей на 1 объект

Или: -

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10 указателей на 10 объектов

Это неэффективно и во всех крупных приложениях может быть значительным.

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

Энтони Бут
источник
9
Неправильно, согласно stackoverflow.com/questions/1881922/… , строка "" будет повторно использована из пула строк.
RealHowTo
1
Я заявил, что он может повторно использовать тот же объект и, если это так, все еще менее эффективен, потому что ему нужно найти этот объект (в пуле строк), так как же я ошибаюсь? Несмотря на это, есть несколько причин, по которым String.Empty превосходит другие, в том числе предотвращение ошибок, таких как myVar = ""; и удобочитаемость, а также улучшение производительности, о котором я уже говорил. Хорошей практикой является использование констант вместо создания строковых литералов, если ни по какой другой причине; легче поддерживать код.
Энтони Бут
1
Я сомневаюсь, что ваш аргумент производительности действителен, потому что JLS говорит, что константа будет считаться литералом во время компиляции ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ) Удобочитаемость - лучший аргумент.
RealHowTo
3
@AntonySmith - я думаю, вам нужно немного больше изучить Java или, возможно, вы уже знаете свою ошибку. Строки Java неизменны и находятся в пуле. Таким образом, в JVM есть только ОДИН объект String для "", независимо от того, сколько раз он найден в коде. Вы можете проверить, пуста ли строка, выполнивif (text == "")
Ajoy Bhatia
2
Неправильно. Этот комментарий следует удалить.
Элад Табак