Чому 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?


17
Я б запропонував замінити "Чому дизайнери Java не подумали про X" на "Чому дизайнери Java вирішили проти X". Надайте їм основний кредит того, що він не є сліпим до вибору.
Авнер Шахар-Каштан

5
nullє винятковим станом і з ним слід звертатися явно.
CodesInChaos

2
@KonradMorawski: Особисто я вважаю, що це жорстоке використання методів розширення. Якщо у вас є нульове значення, то, що на землі ви намагаєтеся викликати методи на ньому, ви просто заплутаєте всіх, хто читає цей код. Maybe<T>Думаю , це погана реалізація типу.
Фоши

1
@Phoshi один має мати на увазі , що методи розширення не є реальними методами, вони просто синтаксисом. Але я згоден, що це суперечливо. Я хотів би, щоб C # / Java запропонував якусь вбудовану синтаксичну нульову безпеку, як-от скажімо - Котлін. string name = employee?.personalData?.name. Так само як ярлик для всіх цих повторюваних if (employee != null)s. Питання, пов'язані ТА: stackoverflow.com/questions/1196031/…
Конрад Моравський

2
@ADTC Помилка , ви розумієте, що програма не може заздалегідь передбачити, що значення є нульовим, правда? - Вам слід визначити контракти між вашими інтерфейсами таким чином, щоб ви могли бути впевнені, чи дозволено значення для нуля чи ні. Перевірка нуля скрізь означає, що у вас є проблема дизайну програми.
Uooo

Відповіді:


30

Повернення null має для мене сенс, оскільки маніпулювання рядком null повинно призвести до нульового рядка, а не до помилки

Ну, це ваша думка. Інші можуть аргументувати, що String-операції над нульовим об'єктом, який не містить String, не мають сенсу, і, отже, слід викинути Виняток

Чому «дизайнери Java» щось робили чи не робили, важко відповісти.

Тут уже є бібліотеки, які можуть робити безпечні струнні операції, наприклад StringUtils Apache Commons. Ви можете використовувати ту чи подібні бібліотеки, якщо вони вам потрібні.


Додавання на основі ваших коментарів

Читаючи коментарі, здається, що справжня проблема, з якою ви стикаєтесь, полягає в тому, що вам доведеться перевіряти nullвесь код. Це може бути показником поганого дизайну програми без чітко визначених контрактів між інтерфейсами. Можливо, ви хочете прочитати Уникання тверджень "! = Null" на Java?


1
Дякуємо за ваш відгук. Я думаю, що справжнє питання полягає в тому, чому ми повинні залежати від зовнішньої бібліотеки чи домашніх класів, коли таку основну особливість можна зробити частиною стандартної Java?
ADTC

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

Одним із способів поводження з нулями є використання гуави Optional- code.google.com/p/guava-libraries/wiki/…
Конрад Моравський

10

IMO весь підхід "if arg is null return null" до методів написання непотрібно збільшує циклічну складність вашої програми.

Ранні версії Java використовували підхід повернення нуля, але хлопці JDK завжди захищали від нуля за винятком.

З часом, я думаю, останній підхід став явним переможцем.

Чому? Оскільки нульові поля порушують багато принципів oo. Ви просто не можете ставитися до них як до членів поліморфного класу. Це означає, що вам завжди доводиться кодувати спеціальні випадки для нуля, а значить, ваша цикломатична складність зникає, коли ви повинні припустити, що речі можуть бути недійсними.

Щоб вирішити свої проблеми, розгляньте можливість використання нульового шаблону об'єкта замість того, щоб покладатися на нульові поля.


2
Але Stringхіба це не поліморфно, ні? І як ви використовуєте нульовий шаблон об'єкта для вже існуючого типу типу String?
svick

Рядок не поліморфний, ні. Але навіть тому ви хотіли б знати, що ви можете викликати методи екземпляра на будь-який посилання на рядок, який у вас є. Це працює для всіх ненульових посилань. У рядку вже є нульовий об’єкт: порожній рядок. Так само, як у списків є порожній список. Тож запитайте себе, чому порожнього рядка у вашому випадку недостатньо. Я думаю, що ви використовуєте нульову рядок для позначення якогось особливого випадку. Запитайте себе, чи можете ви використовувати окремий прапор для цього особливого випадку.
Олександр Торстлінг

@AlexanderTorstling: поле типу intза замовчуванням до нуля, а не null. Концептуально має бути можливість мати stringтип, значення за замовчуванням якого було б порожнім рядком, а не null[такий тип може бути семантично таким, Stringщо intмає бути Integer]. Те, що непусте порожнє stringвнутрішнє посилання на об'єкт купи, було б детальною інформацією про реалізацію; немає причин, щоб він не міг вести себе семантично як примітив.
supercat

@supercat: Погоджено. Я думаю, було б краще заборонити нульові значення для референтів, якщо прямо не включено. Поле за замовчуванням та кінцеві поля. У багатьох типах вже є об’єкти
недійсної

@AlexanderTorstling: наявність місць зберігання всіх типів за замовчуванням до байт-нуля, а також надання типів структури можна призначити за допомогою байтової копії, значно спрощує рамку, але в значній мірі означає, що типи з змінною посилальною семантикою повинні за замовчуванням нуль. Було б корисно, однак, мала б підтримка фреймворку для типів значень, які мали б інкапсулювати єдину посилання і "поле", як - і могло б відстебнути - цей тип посилання .
supercat

3

Не кажучи, що це причина, але, за винятком toString, усі ці методи легко інкапсулюються в статичний хелперний клас, тоді як зворотне не відповідає дійсності.

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


Хороший момент, хоча більше коментаря, ніж відповіді. Але навіть враховуючи це, чому ми мусимо залежати від зовнішньої бібліотеки чи домашніх класів, коли таку основну особливість можна зробити частиною стандартної Java?
ADTC

2
На сьогодні у вас є String.format(статичний), але ви не можете цього зробити "something %s".format(id).
Конрад Моравський

@adtc: тому що це не є основною особливістю мови робити це за допомогою статичного класу. Починаючи з цієї передумови, є багато причин цього не робити - непотрібний розрив коду / коду, дублювання функціональності, вартість розробки / обслуговування.
jmoreno

-2

У Java ця струна є об'єктом. Це вибір дизайну.

Посилання на об'єкти можуть бути нульовими та нульовими, якщо йому не призначений об'єкт. Якщо ви викликаєте такий об'єкт, NullPointerException буде кинуто. Це стандартна поведінка уо.

Дизайнери Java зробили вибір об'єктів рядків як об'єкт, і ці методи викидають винятки з нульовими покажчиками - це те, що ви отримуєте, якщо хочете, щоб рядки були об'єктами.

Чому дизайнери Java не думали про це, коли розробляли клас String на Java 1 або Java 2, або навіть додавали таку функціональність у більш пізній версії Java?

Вони, напевно, думали про це і вирішили включити поведінку.


Чи можу я знати, як створюється статичні методи для опіки нульових випадків, а не поведінки ОО ? Щоб було зрозуміло, я не кажу, що це так, але я намагаюся зрозуміти, чому ви говорите, що проектне рішення полягає у включенні поведінки OO.
ADTC

Статичні методи більше схожі на функції. І для потрібного вам використання вони навіть не повинні входити до рядкового класу, а бути частиною класу корисності. Подібно до функцій класу математики.
Пітер Б

4
Тільки тому, що рядки є об'єктами, не означає, що клас String не може мати статичні методи. І справді це вже є деякі, напр. String.format. (Те саме в C #, до речі). Отже, якщо це вибір дизайну, він не може виходити виключно з того, що рядки є об'єктами, і він не застосовується послідовно.
Конрад Моравський

@PieterB Я б не скаржився, якби принаймні такі методи були передбачені у Stringsкорисному класі, як у нас є Arraysклас корисності ( хоча я розумію, що він створений із чистої необхідності через масиви, які є дивним схрещуванням між примітивами та об'єктами: ) ) .. до тих пір, поки він був частиною стандартної Java та не потребував залежностей.
ADTC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.