Чому на Java немає String.Empty?


260

Я розумію, що кожного разу, коли я набираю літеральний рядок "", на той же об'єкт String посилається в пуловому рядку.

Але чому API String не містить a public static final String Empty = "";, тому я можу використовувати посилання на String.Empty?

Це дозволило б заощадити час компіляції, як мінімум, оскільки компілятор буде знати посилання на існуючу String, і не доведеться перевіряти, чи він уже створений для повторного використання, правда? І особисто я думаю, що розповсюдження рядкових літералів, особливо крихітних, у багатьох випадках - це "запах коду".

Тож чи не було грандіозних причин дизайну за жодним String.Empty, чи творці мови просто не поділили мої погляди?


5
Aidanc: Я думаю , що він мав в виду ситуації , коли ви робите такі речі , як outputBlah = ""і він , ймовірно , вважає за краще something == String.Emptyбільше , something.Length > 0а також (пропустити перевірку нульовий.)
Skurmedel

2
@Aidanc - Він шукав такого "порожнього члена", як Collections.EMPTY_SET , а не функцію перевірки на наявність рядкової "порожнечі".
Тім Стоун

2
@Aidanc: Те, що надихнуло це, насправді "TextBox.setText (" "); '.
Том Тресанський

3
Є String.isEmpty()функція ... навіщо ви хочете String.EMPTY?
Buhake Sindi

8
String.isEmpty()не повертає порожній рядок.
Стів Куо

Відповіді:


191

String.EMPTY- це 12 символів, і ""це два, і вони обидва посилаються на один і той же екземпляр у пам'яті під час виконання. Я не зовсім впевнений, навіщо String.EMPTYекономити час на компіляцію, адже я думаю, що це було б останнє.

Особливо враховуючи, що Strings є незмінними, це не так, як ви можете спочатку отримати порожню струну і виконати деякі операції над нею - найкраще скористатись StringBuilder(або StringBufferякщо ви хочете бути захищеним від потоку) і перетворити це на String.

Оновити
З коментаря до питання:

Що насправді це надихнуло TextBox.setText("");

Я вважаю, що було б цілком законно надати константу у відповідному класі:

private static final String EMPTY_STRING = "";

А потім посилайтеся на це як у своєму коді як

TextBox.setText(EMPTY_STRING);

Оскільки таким чином ви принаймні виясняєте, що хочете порожню рядок, а не забули заповнити рядок у вашому IDE або щось подібне.


14
Я все одно поставлю вам +1, але я відчуваю себе брудною, тому що ви згадали, StringBuilderне розмовляючи про те, як дев'ять разів із десяти це зовсім недоцільно використовувати, StringBuilderа не конкатенацію.
Рандольфо

84
Я, як правило, віддаю перевагу string.empty, здебільшого тому, що це більш явно. Крім того, є ситуації з швидкістю, коли візуально диференціювати "" та такі речі, як "" "може бути важче. Зрештою, як зазначають інші, це лише одна з тих безглуздих речей, що дають нам корм сперечатися, коли нам нудно реально працювати. =)
JohnFx

@Nodel M: Що стосується часу компіляції, я вважаю, що якщо є два рядкові літерали, визначені у двох різних вихідних файлах з однаковим значенням рядка, коли компілятор потрапляє на другий, він повинен зробити певну перевірку, щоб з'ясувати " ей, я вже знаю про цю струну ззаду ". Я, правда, не є експертом компілятора Java, але як це НЕ могло бути? І я думаю, що пропуск цього перевірки призведе до незначного покращення часу компіляції.
Том Тресанський

@Tom - Я вважаю, що інтернування інтерфейсу проводиться під час виконання, а не час компіляції, тому насправді, якщо у вас є порожня рядок як константа в іншому файлі, компілятору потрібно посилатись на цей клас, щоб вирішити лінгер String.
Ноель М

1
@Randolpho Під час використання рядкового конкатенації ви фактично використовуєте StringBuilder під кришкою.
whiskeysierra

133

Використовуйте org.apache.commons.lang.StringUtils.EMPTY


29
Виглядає набагато приємніше і легше для читання, ніж порожній "". Я сподіваюся, що це не тільки я.
Lakatos Gyula

2
@LakatosGyula - я думаю, що це може бути (тільки ти). У досвідчених програмістів Java немає проблем із читанням ""... і , мабуть, більшість із них, можливо, голосно заперечує проти використання, за EMPTYвинятком конкретних ситуацій, коли EMPTYмає конкретне значення для домену. (І в таких випадках, мабуть, є більш відповідне ім’я.)
Stephen C

14
@LakatosGyula Це не лише ти. Я перейшов від Java до розробки .NET, і String.Empty була особливістю, яку я із задоволенням знайшов у рамках. Мені подобається чіткий характер його через порожній набір цитат.
yohohoho

63
@StephenC Коли я бачу порожній "", перше, що скаче в голові, що це помилка, хтось не закінчив функцію тощо. З String.EMPTY я точно знаю, що розробник мав намір повернути порожній рядок.
Лакатос Гюла

1
Також корисно для всіх тих часів, коли в лайнері сказано: "використовуйте названу константу замість бла-бла-бла". Кожен програміст знає, що це не магія, але краще не пояснювати це замовнику.
LizH

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
Давор

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 - знову не нульовий безпечний. Також не враховує рядки пробілів.
  • Порівняння з постійною EMPTY - Не може бути безпечним для нуля. Проблема пробілів

Granted StringUtils - це ще одна бібліотека, яку можна перетягнути, але вона працює дуже добре і економить багато часу і клопоту перевіряє наявність нулей або витончено поправляє NPE.


3
так ... це , здається , єдиний безпечний варіант жахливого стан Yoda: "".equals(s)?
Лі Лі Раян

8

Не кажіть просто: "Пам'ять рядків рядків повторно використовується в прямому вигляді, випадок закритий". Що робити компілятори під кришкою, тут не суть справи. Питання обґрунтоване, особливо враховуючи кількість отриманих голосів.

Йдеться про симетрію , без неї API важче використовувати для людини. Ранні SDK-пакети Java, як відомо, ігнорували це правило, а тепер вже занадто пізно. Ось кілька прикладів на моїй голові, не соромтеся чіпнути ваш "улюблений" приклад:

  • BigDecimal.ZERO, але немає AbstractCollection.EMPTY, String.EMPTY
  • Array.length, але List.size ()
  • List.add (), Set.add (), але Map.put (), ByteBuffer.put (), і не будемо забувати StringBuilder.append (), Stack.push ()

Навіть якщо ви назвали параметр List length (), вам все одно потрібні дужки, оскільки це метод. Array.length - це публічна остаточна змінна, яка працює лише тому, що масиви незмінні. Отже, у вас все ще будуть Array.length та List.length (). Я б заперечив, що це більш заплутано і схильне до помилок. Що стосується .append () та .push (), тоді як вони виконують подібні завдання, я думаю, що вони назвали відповідним чином. Додавання рядка - це саме те, що ви робите, але ви не "додаєте" стек, ви натискаєте та додаєте значення. І StringBuilder.push () буде означати StringBuilder.pop (), що неможливо.
Крейг Партон

Починаючи з шаблонів / дженериків, послідовні інтерфейси також допомагають алгоритмам. Якщо алгоритму потрібна довжина колекції, то все, що нам потрібно, - довжина (T) або T.length (). Аналогічно, додавання до кінця стека, списку або рядка може бути виконано універсальним add () або append (). Ви згадали, що масив у Java незмінний / вбудований тип із властивістю відкритої довжини. Це добре, це не означає, що компілятор не може обробляти або генерувати код для довжини (T) або T.length (). Котлін генерує ряд властивих методів для різних випадків.
Славомир

Але послідовно названий метод length () дозволяє лише перевірити довжину. Наскільки це корисно? Якщо ваша мета полягає в абстрактних списках і масивах, щоб зробити якийсь придатний для використання через інтерфейс, вам також потрібен послідовний спосіб читання або запису даних. Тож тепер вам потрібно генерувати методи get (), set () та add (). По суті, ви створюєте менш функціональний перегляд списку масиву. Оскільки Arrays.asList () доступний, простий у використанні та легкий, навіщо винаходити колесо? Масиви, списки, StringBuilders та стеки мають певне призначення. Здається, краще розробити інтерфейс, щоб він найкраще підходив.
Крейг Партон

5

Усі ці ""літерали - це той самий об’єкт. Навіщо робити все це зайвою складністю? Це просто довше набирати та менш зрозуміло (вартість компілятора мінімальна). Оскільки рядки Java - це незмінні об'єкти, ніколи взагалі не виникає необхідності розрізняти їх, за винятком можливостей як ефективності, але з пустим літеральним рядком - це не велика справа.

Якщо ви дійсно хочете EmptyStringпостій, зробіть це самостійно. Але все, що він буде робити, - це заохочувати ще більше деталізований код; від цього ніколи не буде користі.


27
x = String.Emptyпередає наміри краще, ніж x = "". Останнє може бути випадковим упущенням. Сказати, що користі ніколи не буває, невірно.
Джефрі Л Вітлідж

@ Джефрі: Я не думаю, що я особливо згоден. Це одна з таких речей, де я думаю, що немає жорсткого і швидкого правила.
Стипендіати доналу

Так, важливо зазначити, що компілятор 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

Я розумію, що кожного разу, коли я набираю Stral literal "", на той самий String об'єкт посилається в пулу String.
Ніякої такої гарантії не зроблено. І ви не можете покластися на це у своїй заявці, вирішувати jvm повністю.

чи творці мови просто не поділили мої погляди?
Так. Мені це здається дуже низькою пріоритетною справою.


6
Ніякої такої гарантії не зроблено ... Ну, JLS констатує, що це має бути так.
Тім Стоун

@Tim Ні, якщо ви не зробите «стажування». Побудувати дві рівні великі рядки легко і програмно.
Микита Рибак

@Tim Наприклад, повторіть a + = "a"; 100 разів зробіть те ж саме з b і перевірте.
Микита Рибак

5
Ви маєте рацію, але те, що ви описали, не є рядковим літералом і не виразом, результат якого можна гарантувати під час компіляції (наприклад, String username = "Bob" + " " + "Smith";). Струни, створені програмно, не мають гарантій інтернації, якщо ви прямо не зателефонували, intern()як ви заявили. Сценарій ОП описує використання пустого рядкового літералу в ""усьому коді, що є випадком, коли відбудеться автоматичне інтернування.
Тім Стоун

@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.


-16

Для тих , хто стверджує ""і String.Emptyє взаємозамінними або що ""краще, ви сильно помиляєтеся.

Кожен раз, коли ви робите щось на зразок myVariable = ""; ви створюєте екземпляр об’єкта. Якщо в об’єкті String Java була загальнодоступна константа 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/… , рядок "" буде повторно використаний з пулу String.
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 є лише "ONE String" об'єкт для незалежної кількості, скільки разів він знайдений у коді. Ви можете перевірити, чи рядок порожній, зробивши цеif (text == "")
Ajoy Bhatia

2
Неправильно. Цей коментар слід видалити.
Елад Табак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.