Почему в Java String нет методов статической обработки строк?

17

Почему разработчики Java не создали статические версии методов манипуляции со строками в java.lang.Stringклассе? Следующие методы - это то, к чему я обращаюсь, но вопрос можно распространить и на другие нестатические методы в классе.

concat(String)                        substring(int, int)
replace(char, char)                   toLowerCase()
replace(CharSequence, CharSequence)   toLowerCase(Locale)
replaceAll(String, String)            toString()
replaceFirst(String, String)          toUpperCase()
split(String)                         toUpperCase(Locale)
split(String, int)                    trim()
substring(int)

Наличие только нестатических версий этих методов вызывает явную проверку нуля везде, где должен вызываться такой метод. Например, простой вызов example = example.trim()приведет к NullPointerException, если String example = null. Таким образом, программист должен выполнить следующую проверку нуля:

if (example != null)
    example = example.trim();
// OR:
example = (example==null) ? null : example.trim();
example = (example==null) ? null : example.substring(5);

Я полагаю, что было бы намного удобнее, если бы Stringимелись статические версии этих методов (возможно, даже исключительно ), которые бы принимали входную строку в качестве первого аргумента:

example = String.trim(example);
example = String.replace(example, 'a', 'b');
example = String.substring(example, 5);

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

Почему разработчики Java не думали об этом, когда разрабатывали Stringкласс в Java 1 или Java 2, или даже не добавляли такую ​​функциональность в более позднюю версию Java?

ADTC
источник
17
Я бы предложил заменить «Почему Java-дизайнеры не думают о X» на «Почему Java-дизайнеры приняли решение против X». Дайте им основной кредит не быть слепым к варианту.
Авнер Шахар-Каштан
5
nullявляется исключительным состоянием и должно обрабатываться явно.
CodesInChaos
2
@KonradMorawski: Лично я считаю, что грубое неправильное использование методов расширения. Если у вас есть нулевое значение, то что вы делаете, пытаясь вызвать методы, вы просто запутаете всех, кто читает этот код. Maybe<T>Думаю , это плохая переопределение типа?
Phoshi 12.12.13
1
@Phoshi один имеет иметь в виду , что методы расширения не являются реальными методами, они просто синтаксисом. Но я согласен , что это спорно. Я хотел бы, чтобы C # / Java предлагал какую-то встроенную синтаксическую нуль-безопасность, как, скажем, Kotlin. string name = employee?.personalData?.name, Просто как ярлык для всех этих повторяющихся if (employee != null)с. Соответствующий вопрос SO: stackoverflow.com/questions/1196031/…
Конрад Моравский
2
@ADTC Эрм, вы понимаете, что программа не может заранее предсказать, что значение равно нулю, верно? - Вы должны определить контракты между вашими интерфейсами таким образом, чтобы вы могли быть уверены, что значение может быть нулевым или нет. Нулевая проверка везде означает, что у вас есть проблема разработки программы.
Uooo

Ответы:

30

Возвращение нуля имеет смысл для меня, так как манипулирование пустой строкой должно привести к пустой строке, а не к ошибке

Ну, это ваше мнение. Другие могут утверждать, что операции String над нулевым объектом, который не содержит String, не имеют смысла и, следовательно, должны выдавать исключение

Почему «дизайнеры Java» сделали или не сделали что-то, трудно ответить.

Уже есть библиотеки, которые могут выполнять операции String с нулевой безопасностью, например StringUtils из Apache Commons. Вы можете использовать эту или аналогичные библиотеки, если они вам нужны.


Дополнение на основе ваших комментариев

Читая комментарии, кажется, что реальная проблема, с которой вы сталкиваетесь, заключается в том, что вы должны проверять nullвесь код. Это может быть индикатором плохого дизайна программы без четко определенных контрактов между интерфейсами. Возможно, вы захотите прочитать Избегание «! = Null» операторов в Java?

UOOO
источник
1
Спасибо за ваш отзыв. Я предполагаю, что реальный вопрос заключается в том, почему мы должны зависеть от внешней библиотеки или классов домашнего приготовления, когда такую ​​базовую функцию можно сделать частью стандартной Java?
ADTC
4
@ ADTC давайте поставим вопрос наоборот: зачем «дизайнерам Java» включать что-то в язык, если уже есть много хороших библиотек, хорошо протестированных и задокументированных? Как определить «основную особенность» на основе мнения. Разве в большинстве проектов не требуется какая-либо внешняя библиотека для «базовой функциональности» (модульное тестирование, макетирование, дата и время, ...)? Это не имеет большого значения, не так ли?
Ууууу
Один из способов справиться с пустыми значениями - использовать Guava's Optional- code.google.com/p/guava-libraries/wiki/…
Конрад Моравский
10

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

Ранние Java-библиотеки использовали метод return null, но ребята из JDK всегда защищали от null с исключениями.

Со временем я думаю, что последний подход стал явным победителем.

Почему? Так как нулевые поля нарушают многие принципы. Вы просто не можете относиться к ним как к членам полиморфного класса. Это означает, что вы всегда должны кодировать особые случаи для нуля, и, следовательно, ваша цикломатическая сложность возрастает, когда вы должны предположить, что вещи могут быть нулевыми.

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

Александр Торстлинг
источник
2
Но Stringразве не полиморфно, нет? И как вы используете шаблон нулевого объекта для уже существующего типа, такого как String?
svick
Строка не полиморфная, нет. Но даже в этом случае вы хотели бы знать, что вы можете вызывать методы экземпляра для любой имеющейся у вас строковой ссылки. Это работает для всех ненулевых ссылок. У строки уже есть нулевой объект: пустая строка. Также как списки имеют пустой список. Поэтому спросите себя, почему пустой строки недостаточно в вашем случае. Я предполагаю, что вы используете пустую строку, чтобы отметить какой-то особый случай. Спросите себя, можете ли вы использовать отдельный флаг для этого особого случая.
Александр Торстлинг 12.12.13
@AlexanderTorstling: поле типа по intумолчанию равно нулю, а не null. Концептуально должно быть возможно иметь stringтип, значением по умолчанию которого будет пустая строка, а не null[такой тип может быть семантически относящимся к Stringтому, что intнужно Integer]. Тот факт, что непустое stringбудет внутренне содержать ссылку на объект кучи, будет деталью реализации; нет причины, по которой он не мог бы вести себя семантически как примитив.
суперкат
@supercat: Согласен. Я думаю, что было бы лучше запретить нулевые значения для ссылок, если явно не включено. Не пустые и окончательные поля по умолчанию. Многие типы уже имеют объекты с нулевым поведением
Александр Торстлинг
@AlexanderTorstling: наличие в хранилищах всех типов по умолчанию значения all-bytes-zero и обеспечение возможности назначения типов структуры с помощью all-bytes-copy, значительно упрощает структуру, но в значительной степени подразумевает, что типы с изменяемой ссылочной семантикой должны по умолчанию иметь значение значение NULL. Однако было бы полезно иметь каркасную поддержку для типов значений, которые инкапсулировали бы единственную ссылку и могли бы «вставлять» как - и могли бы распаковать из - этот ссылочный тип .
суперкат
3

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

Т.е. если вы хотите Stings.toUpper (строковый ввод), то код для этого легко написать, но если вы хотите instance.toUpper и все, что у вас есть, это String.toUpper, ну, это невозможно ... если они не вводят методы расширения, который, скорее всего, даже не рассматривался в то время.

jmoreno
источник
Хороший вопрос, хотя это скорее комментарий, чем ответ. Но даже с учетом этого, почему мы должны зависеть от внешней библиотеки или классов домашнего приготовления, когда такую ​​базовую функцию можно сделать частью стандартной Java?
ADTC
2
На данный момент у вас есть String.format(статический), но вы не можете сделать "something %s".format(id).
Конрад Моравский
@adtc: потому что это не основная особенность языка - делать это через статический класс. Исходя из этой предпосылки, есть много причин, по которым этого не следует делать: ненужный код / ​​разложение кода, дублирующиеся функциональные возможности, стоимость разработки / обслуживания.
Jmoreno
-2

В Java эта строка является объектом. Это выбор дизайна.

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

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

Почему разработчики Java не думали об этом, когда они разрабатывали класс String в Java 1 или Java 2, или даже добавляли такую ​​функциональность в более позднюю версию Java?

Они, наверное, думали об этом и решили включить в себя oo-поведение.

Питер Б
источник
Могу ли я знать, как создание статических методов для решения нулевых случаев, а не поведения OO ? Чтобы было ясно, я не говорю, что это так, но я пытаюсь понять, почему вы говорите, что проектное решение заключается в том, чтобы включить поведение ОО.
ADTC
Статические методы больше похожи на функции. И для использования, которое вы хотите, они даже не должны быть частью строкового класса, а должны быть частью некоторого служебного класса. Так же, как математические функции класса.
Питер Б
4
Тот факт, что строки являются объектами, не означает, что класс String не может иметь статических методов. И действительно, он уже есть, например. String.format, (То же самое в C #, кстати). Так что, если это выбор дизайна, он не может исходить исключительно из того факта, что строки являются объектами, и он не применяется последовательно.
Конрад Моравский
@PieterB Я бы не стал жаловаться, если бы по крайней мере такие методы были предоставлены в Stringsслужебном классе, как, например, у нас есть Arraysслужебный класс ( хотя я понимаю, что он был создан из-за чистой необходимости из-за того, что массивы представляют собой некое странное сочетание между примитивами и объектами: ) ) .. пока он был частью стандартной Java и не требовал зависимостей.
ADTC