Warum verfügt Java String nicht über Methoden zur Bearbeitung statischer Zeichenfolgen?

17

Warum haben Java-Designer in der java.lang.StringKlasse keine statischen Versionen von String-Manipulationsmethoden erstellt ? Die folgenden Methoden sind das, worauf ich mich beziehe, aber die Frage kann auch auf andere nicht statische Methoden in der Klasse ausgeweitet werden.

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)

Wenn nur nicht statische Versionen dieser Methoden vorhanden sind, wird die explizite Nullprüfung überall dort erzwungen, wo eine solche Methode aufgerufen werden muss. Zum Beispiel example = example.trim()würde ein einfacher Aufruf zu NullPointerException if führen String example = null. Der Programmierer muss also den folgenden Null-Check für das Boilerplate durchführen:

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

Ich würde mir vorstellen, dass es viel praktischer gewesen wäre, wenn Stringstatische Versionen dieser Methoden (vielleicht sogar ausschließlich ) verwendet worden wären, bei denen die Eingabezeichenfolge als erstes Argument herangezogen würde:

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

Dies hätte zu einem saubereren Code geführt, der von Programmierern geschrieben wurde und der sich automatisch um Nullfälle gekümmert hätte, indem einfach Null zurückgegeben wurde, anstatt die Programmierer zu zwingen, explizit Nullfälle zu behandeln. Die Rückgabe von null ist für mich sinnvoll, da die Manipulation einer Nullzeichenfolge zu einer Nullzeichenfolge und nicht zu einem Fehler führen sollte.

Warum haben Java-Designer nicht daran gedacht, als sie die StringKlasse in Java 1 oder Java 2 entworfen oder in einer späteren Java-Version sogar eine solche Funktionalität hinzugefügt haben?

ADTC
quelle
17
Ich würde vorschlagen, "Warum haben Java-Designer nicht an X gedacht" durch "Warum haben sich Java-Designer gegen X entschieden" zu ersetzen. Geben Sie ihnen die grundlegende Ehre, nicht blind für die Option zu sein.
Avner Shahar-Kashtan
5
nullist ein Ausnahmezustand und sollte ausdrücklich behandelt werden.
CodesInChaos
2
@KonradMorawski: Ich persönlich finde, dass ein grober Missbrauch von Erweiterungsmethoden. Wenn Sie einen Nullwert haben, was um alles in der Welt tun Sie dann, um Methoden aufzurufen, werden Sie nur jeden verwirren, der diesen Code liest. Es ist eine schlechte Neuimplementierung eines Maybe<T>Typs, denke ich?
Phoshi
1
@Phoshi man muss bedenken, dass Erweiterungsmethoden KEINE echten Methoden sind, sondern nur Syntaxzucker. Aber ich stimme zu, dass es umstritten ist. Ich wünschte, C # / Java hätte eine Art eingebaute syntaktische Nullsicherheit geboten, wie beispielsweise Kotlin. string name = employee?.personalData?.name. Nur als Abkürzung für all diese sich wiederholenden if (employee != null)s. Verwandte SO Frage: stackoverflow.com/questions/1196031/…
Konrad Morawski
2
@ADTC Ähm , Sie wissen, dass ein Programm nicht im Voraus vorhersagen kann, dass ein Wert null ist, oder? - Sie sollten die Verträge zwischen Ihren Schnittstellen so definieren, dass Sie sicher sein können , ob ein Wert null sein darf oder nicht. Wenn Sie überall auf Null prüfen, haben Sie ein Problem mit dem Programmdesign.
Uooo

Antworten:

30

Die Rückgabe von null ist für mich sinnvoll, da die Manipulation einer Nullzeichenfolge zu einer Nullzeichenfolge und nicht zu einem Fehler führen sollte

Nun, das ist deine Meinung. Andere argumentieren möglicherweise, dass Zeichenfolgenoperationen für ein Nullobjekt, das keine Zeichenfolge enthält, keinen Sinn ergeben und daher eine Ausnahme auslösen sollten

Warum "Java-Designer" etwas getan oder nicht getan haben, ist schwer zu beantworten.

Es gibt bereits Bibliotheken, die nullsichere String-Operationen ausführen können, z. B. StringUtils von Apache Commons. Sie können diese oder ähnliche Bibliotheken verwenden, wenn Sie sie benötigen.


Hinzufügung basierend auf Ihren Kommentaren

Beim Lesen der Kommentare scheint das eigentliche Problem zu sein, dass Sie den nullgesamten Code überprüfen müssen. Dies kann ein Hinweis auf ein schlechtes Programmdesign ohne klar definierte Verträge zwischen den Schnittstellen sein. Möglicherweise möchten Sie "! = Null" -Anweisungen in Java vermeiden lesen ?

Uooo
quelle
1
Vielen Dank für Ihr Feedback. Ich denke, die eigentliche Frage ist, warum wir uns auf eine externe Bibliothek oder selbst gebraute Klassen verlassen müssen, wenn solch eine grundlegende Funktion Teil des Java-Standards sein kann.
ADTC
4
@ADTC lasst uns die Frage umgekehrt stellen: Warum sollten "Java-Designer" etwas in die Sprache aufnehmen, wenn es bereits viele gute Bibliotheken gibt, die gut getestet und dokumentiert sind? Wie man ein "Grundmerkmal" definiert, ist meinungsbasiert. Benötigt nicht fast jedes Projekt eine externe Bibliothek für "Basisfunktionalität" (Komponententest, Verspotten, Datum und Uhrzeit, ...)? Es ist keine große Sache, oder?
Uooo
Eine Möglichkeit , mit Nullen Umgang wird mit Guava des Optional- code.google.com/p/guava-libraries/wiki/...
Konrad Morawski
10

IMO erhöht der gesamte Ansatz "if arg is null return null" zum Schreiben von Methoden unnötigerweise die zyklomatische Komplexität Ihres Programms.

Frühe Java-Bibliotheken verwendeten den Return-Null-Ansatz, aber die JDK-Leute schützten sich immer mit Ausnahmen vor Null.

Ich denke, mit der Zeit hat sich der letztgenannte Ansatz als klarer Gewinner herausgestellt.

Warum? Da Nullfelder eine Menge von OO-Prinzipien brechen. Sie können sie einfach nicht als Mitglieder einer polymorphen Klasse behandeln. Dies bedeutet, dass Sie immer Sonderfälle für null codieren müssen, und daher steigt Ihre zyklomatische Komplexität an, wenn Sie davon ausgehen müssen, dass die Dinge null sein können.

Um Ihre Probleme zu lösen, sollten Sie das Nullobjektmuster verwenden, anstatt sich auf Nullfelder zu verlassen.

Alexander Torstling
quelle
2
Aber Stringist nicht polymorph, nein? Und wie benutzt man das Null-Objektmuster für einen bereits existierenden Typ wie String?
Svick
String ist nicht polymorph, nein. Trotzdem möchten Sie wissen, dass Sie Instanzmethoden für jede Zeichenfolgenreferenz aufrufen können, die Sie haben. Dies funktioniert für alle Nicht-Null-Referenzen. String hat bereits ein Null-Objekt: den leeren String. Genau wie Listen haben die leere Liste. Fragen Sie sich also, warum die leere Zeichenfolge in Ihrem Fall nicht ausreicht. Ich vermute, dass Sie eine Null-Zeichenfolge verwenden, um einen Sonderfall zu kennzeichnen. Fragen Sie sich, ob Sie für diesen speziellen Fall eine separate Flagge verwenden können.
Alexander Torstling
@AlexanderTorstling: Ein Feld vom Typ ist intstandardmäßig Null anstatt null. Konzeptionell sollte es möglich sein, einen stringTyp zu haben, dessen Standardwert eine leere Zeichenfolge ist, anstatt null[ein solcher Typ könnte semantisch dem entsprechen, Stringwas intzu sein hat Integer]. Die Tatsache, dass ein nicht leeres stringObjekt intern einen Verweis auf ein Heap-Objekt enthält, ist ein Implementierungsdetail. Es gibt keinen Grund, warum es sich nicht semantisch wie ein Primitiv verhalten könnte.
Supercat
@supercat: Einverstanden. Ich denke, es wäre besser gewesen, Nullwerte für Referenzen zu verbieten, es sei denn, dies wurde ausdrücklich aktiviert. Standardmäßige Nicht-Null- und Endfelder. Viele Typen haben bereits
Nullverhaltensobjekte
@AlexanderTorstling: Wenn Speicherorte aller Typen standardmäßig auf Null gesetzt sind und Strukturtypen über eine All-Byte-Kopie zugewiesen werden können, vereinfacht dies das Framework erheblich, impliziert jedoch, dass Typen mit einer veränderlichen Referenzsemantik standardmäßig den Wert 0 haben müssen Null. Es wäre jedoch hilfreich gewesen, Framework-Unterstützung für Werttypen zu haben, die eine einzelne Referenz kapseln und als diesen Referenztyp "boxen" und aus ihm auspacken könnten .
Supercat
3

Dies ist nicht der Grund, aber mit Ausnahme von toString lassen sich alle diese Methoden leicht in eine statische Hilfsklasse einkapseln, während das Gegenteil nicht zutrifft.

Das heißt, wenn Sie Stings.toUpper (Stringeingabe) wollen, ist der Code dafür einfach zu schreiben, aber wenn Sie instance.toUpper wollen und alles, was Sie haben, ist String.toUpper, na ja, das ist unmöglich ... es sei denn, sie führen Erweiterungsmethoden ein. was damals höchstwahrscheinlich nicht einmal in Betracht gezogen wurde.

jmoreno
quelle
Guter Punkt, obwohl eher ein Kommentar als eine Antwort. Aber selbst wenn man das bedenkt, warum müssen wir uns dann auf eine externe Bibliothek oder selbst gebraute Klassen verlassen, wenn solch eine grundlegende Funktion Teil des Standard-Java sein kann?
ADTC
2
Ab sofort haben Sie String.format(statisch), aber Sie können nicht tun "something %s".format(id).
Konrad Morawski
@adtc: weil es kein grundlegendes Merkmal der Sprache ist, dies über eine statische Klasse zu tun. Ausgehend von dieser Prämisse gibt es viele Gründe, dies nicht zu tun - unnötiger Code / Code Bloat, doppelte Funktionalität, Entwicklungs- / Wartungskosten.
Jmoreno
-2

In Java ist diese Zeichenfolge ein Objekt. Das ist eine Designentscheidung.

Objektreferenzen können null sein und sind null, wenn kein Objekt zugewiesen ist. Wenn Sie ein solches Objekt aufrufen, wird eine NullPointerException ausgelöst. Das ist normales Verhalten.

Java-Designer entschieden sich dafür, Zeichenfolgen als Objekt zu haben und diese Methoden Nullzeiger-Ausnahmen auszulösen, was Sie erhalten, wenn Zeichenfolgen Objekte sein sollen.

Warum haben Java-Designer nicht daran gedacht, als sie die String-Klasse in Java 1 oder Java 2 entworfen oder in einer späteren Java-Version sogar eine solche Funktionalität hinzugefügt haben?

Sie haben wahrscheinlich darüber nachgedacht und beschlossen, oo-Verhalten zu integrieren.

Pieter B
quelle
Darf ich wissen, wie man statische Methoden erstellt, um Nullfälle zu behandeln, und nicht wie man sich verhält ? Um es klar zu sagen, ich sage es nicht, aber ich versuche zu verstehen, warum Sie sagen, dass die Entwurfsentscheidung darin besteht, das OO-Verhalten einzubeziehen.
ADTC
Statische Methoden sind eher Funktionen. Und für die gewünschte Verwendung sollten sie nicht Teil der String-Klasse sein, sondern Teil einer Utility-Klasse. Genau wie Matheklassenfunktionen.
Pieter B
4
Nur weil Strings Objekte sind, kann die String-Klasse keine statischen Methoden haben. Und in der Tat hat es schon einige, z. String.format. (Übrigens auch in C #). Wenn es sich also um eine Designauswahl handelt, kann dies nicht ausschließlich auf die Tatsache zurückzuführen sein, dass Zeichenfolgen Objekte sind, und sie werden nicht konsistent angewendet.
Konrad Morawski
@PieterB Ich würde nicht , wenn zumindest solche Verfahren klagen wurden in einer bereitgestellten StringsUtility - Klasse, wie wir haben ArraysUtility - Klasse ( obwohl ich es erstellt wurde aus purer Notwendigkeit verstehen , aufgrund Arrays eine Art einer seltsamen Kreuzung zwischen Primitiven und Objekten ist: ) ) .. solange es Teil von Standard Java war und keine Abhängigkeiten benötigte.
ADTC