it-swarm.com.de

Verwenden Sie niemals Strings in Java?

Ich bin auf einen Blogeintrag gestoßen, der die Verwendung von Strings in Java) davon abhält, dass Ihr Code keine Semantik aufweist, was darauf hindeutet, dass Sie sollten stattdessen Thin Wrapper-Klassen verwenden. Dies sind die Vorher- und Nachher-Beispiele, die der genannte Eintrag zur Veranschaulichung der Angelegenheit enthält:

public void bookTicket(
  String name,
  String firstName,
  String film,
  int count,
  String cinema);

public void bookTicket(
  Name name,
  FirstName firstName,
  Film film,
  Count count,
  Cinema cinema);

Nach meiner Erfahrung beim Lesen von Programmierblogs bin ich zu dem Schluss gekommen, dass 90% Unsinn sind, aber ich frage mich, ob dies ein gültiger Punkt ist. Irgendwie fühlt es sich für mich nicht richtig an, aber ich konnte nicht genau sagen, was mit dem Programmierstil nicht stimmt.

73
DPM

Die Kapselung schützt Ihr Programm vor change. Wird sich die Darstellung eines Namens ändern? Wenn nicht, verschwenden Sie Ihre Zeit und YAGNI bewirbt sich.

Bearbeiten: Ich habe den Blog-Beitrag gelesen und er hat eine grundsätzlich gute Idee. Das Problem ist, dass er es viel zu weit skaliert hat. So etwas wie String orderIdist wirklich schlecht, weil vermutlich "!"£$%^&*())ADAFVF kein gültiges orderId ist. Dies bedeutet, dass String viel mehr mögliche Werte darstellt als gültige orderIds. Für so etwas wie ein name können Sie jedoch unmöglich vorhersagen, was ein gültiger Name sein könnte oder nicht, und jedes String ist ein gültiges name.

In erster Linie reduzieren Sie (korrekt) die möglichen Eingaben auf nur gültige. Im zweiten Fall haben Sie keine Einschränkung möglicher gültiger Eingaben erreicht.

Erneut bearbeiten: Betrachten Sie den Fall einer ungültigen Eingabe. Wenn Sie "Gareth Gobulcoque" als Ihren Namen schreiben, wird es albern aussehen, es wird nicht das Ende der Welt sein. Wenn Sie eine ungültige Bestell-ID eingeben, funktioniert diese wahrscheinlich einfach nicht.

88
DeadMG

Das ist einfach verrückt :)

46
Makach

Ich stimme dem Autor größtenteils zu. Wenn es ein Verhalten gibt, das einem Feld eigen ist, wie die Validierung einer Auftrags-ID, würde ich eine Klasse erstellen, die diesen Typ darstellt. Sein zweiter Punkt ist noch wichtiger: Wenn Sie eine Reihe von Feldern haben, die ein Konzept wie eine Adresse darstellen, erstellen Sie eine Klasse für dieses Konzept. Wenn Sie in Java programmieren, zahlen Sie einen hohen Preis für die statische Eingabe. Sie können genauso gut den Wert erhalten, den Sie können.

23
kevin cline

Tu es nicht; es wird Sachen überkomplizieren und du wirst es nicht brauchen

... ist die Antwort, die ich vor 2 Jahren hier geschrieben hätte. Nun bin ich mir allerdings nicht so sicher; Tatsächlich habe ich in den letzten Monaten damit begonnen, alten Code in dieses Format zu migrieren, nicht weil ich nichts Besseres zu tun habe, sondern weil ich ihn wirklich brauchte, um neue Funktionen zu implementieren oder vorhandene zu ändern. Ich verstehe die automatischen Abneigungen, die andere hier haben, um diesen Code zu sehen, aber ich denke, das ist etwas, das ernsthafte Überlegungen verdient.


Leistungen

Der Hauptvorteil ist die Fähigkeit, den Code zu ändern und erweitern. Wenn du benutzt

class Point {
    int x,y;
    // other point operations
}

anstatt nur ein paar ganze Zahlen herumzugeben - was leider viele Schnittstellen tun -, wird es viel einfacher, später eine weitere Dimension hinzuzufügen. Oder ändern Sie den Typ in double. Wenn Sie List<Author> authors Oder List<Person> authors Anstelle von List<String> authors Verwenden, wird es später viel einfacher, mehr Informationen zu dem hinzuzufügen, was ein Autor darstellt. Wenn ich es so aufschreibe, fühlt es sich an, als würde ich das Offensichtliche sagen, aber in der Praxis habe ich mich schuldig gemacht, Strings so oft selbst verwendet zu haben, besonders in Fällen, in denen es zu Beginn nicht offensichtlich war, dann würde ich mehr brauchen als ein Faden.

Ich versuche derzeit, eine Zeichenfolgenliste zu überarbeiten, die in meinem Code verflochten ist, da ich dort weitere Informationen benötige und den Schmerz spüre: \

Darüber hinaus stimme ich dem Autor des Blogs zu, dass es mehr semantische Informationen enthält, was dem Leser das Verständnis erleichtert. Während Parameter häufig aussagekräftige Namen erhalten und eine eigene Dokumentationszeile erhalten, ist dies bei Feldern oder Einheimischen häufig nicht der Fall.

Der letzte Vorteil ist Typensicherheit, aus offensichtlichen Gründen, aber in meinen Augen ist es hier eine Kleinigkeit.

Nachteile

Das Schreiben dauert länger. Das Schreiben einer kleinen Klasse ist schnell und einfach, aber nicht mühelos, insbesondere wenn Sie viele dieser Klassen benötigen. Wenn Sie alle 3 Minuten anhalten, um eine neue Wrapper-Klasse zu schreiben, kann dies auch Ihre Konzentration beeinträchtigen. Ich würde jedoch gerne glauben, dass dieser Zustand normalerweise erst in der ersten Phase des Schreibens eines Codes auftritt. Normalerweise kann ich schnell eine ziemlich gute Vorstellung davon bekommen, welche Entitäten involviert sein müssen.

Es können viele redundante Setter (oder Konstruktionen) und Getter beteiligt sein. Der Blog-Autor gibt das wirklich hässliche Beispiel von new Point(x(10), y(10)) anstelle von new Point(10, 10) an, und ich möchte hinzufügen, dass eine Verwendung auch Dinge wie Math.max(p.x.get(), p.y.get()) anstelle von Math.max(p.x, p.y). Und langer Code wird oft zu Recht als schwerer zu lesen angesehen. Aber ganz ehrlich, ich habe das Gefühl, dass eine Menge viel Code Objekte bewegt und nur ausgewählte Methoden sie erstellen, und noch weniger benötigen Zugriff auf das Wesentliche Details (was sowieso nicht OOPy ist).

Fraglich

Ich würde sagen, ob dies bei der Lesbarkeit des Codes hilft oder nicht, ist umstritten. Ja, mehr semantische Informationen, aber längerer Code. Ja, es ist einfacher, die Rolle jedes lokalen Orts zu verstehen, aber es ist schwieriger zu verstehen, was Sie damit tun können, wenn Sie nicht die Dokumentation lesen.


Wie bei den meisten anderen Programmierschulen halte ich es für ungesund, diese auf die Spitze zu treiben. Ich sehe mich nie dabei, die x- und y-Koordinate zu trennen, um jeweils einen anderen Typ zu haben. Ich denke nicht, dass Count notwendig ist, wenn ein int ausreichen sollte. Ich mag die Verwendung von unsigned int In C nicht - obwohl sie theoretisch gut ist, gibt sie Ihnen einfach nicht genügend Informationen und verbietet es, Ihren Code später zu erweitern, um diese magische -1 zu unterstützen. Manchmal braucht man Einfachheit.

Ich denke, dass der Blog-Beitrag etwas extrem ist. Aber insgesamt habe ich aus schmerzhaften Erfahrungen gelernt, dass die Grundidee dahinter aus dem richtigen Material besteht.

Ich habe eine tiefe Abneigung gegen überentwickelten Code. Das tue ich wirklich. Aber richtig verwendet, ich denke nicht, dass dies übertrieben ist.

16
Oak

Obwohl es eine Art Overkill ist, denke ich oft, dass die meisten Dinge, die ich gesehen habe, stattdessen unterentwickelt sind.

Es ist nicht nur "Sicherheit", eines der wirklich schönen Dinge an Java ist, dass es Ihnen sehr hilft, sich daran zu erinnern/herauszufinden, was ein bestimmter Aufruf einer Bibliotheksmethode benötigt/erwartet.

Die (bei weitem) SCHLECHTESTE Java Bibliothek, mit der ich gearbeitet habe, wurde von jemandem geschrieben, der Smalltalk sehr mochte und die GUI-Bibliothek danach modellierte, damit sie sich eher wie Smalltalk verhält - das Problem ist jede Methode nahm das gleiche Basisobjekt, konnte aber nicht alles verwenden, in das das Basisobjekt umgewandelt werden konnte. Sie haben also wieder erraten, was in Methoden übergeben werden soll, und nicht gewusst, ob Sie bis zur Laufzeit fehlgeschlagen sind (etwas, mit dem ich mich früher befassen musste mit jedem Mal, wenn ich in C) arbeitete.

Ein weiteres Problem - Wenn Sie Zeichenfolgen, Ints, Sammlungen und Arrays ohne Objekte weitergeben, haben Sie nur Datenbälle ohne Bedeutung. Dies erscheint natürlich, wenn Sie in Bezug auf Bibliotheken denken, die "einige Apps" verwenden, aber beim Entwerfen einer gesamten App ist es viel hilfreicher, all Ihren Daten an der Stelle, an der die Daten definiert sind, Bedeutung (Code) zuzuweisen und nur zu denken Begriffe, wie diese übergeordneten Objekte interagieren. Wenn Sie Primitive anstelle von Objekten weitergeben, ändern Sie per Definition Daten an einem anderen Ort als dem, an dem sie definiert sind. (Aus diesem Grund mag ich Setter und Getters nicht wirklich - dasselbe Konzept, das Sie verwenden auf Daten, die nicht Ihre sind).

Wenn Sie separate Objekte für alles definieren, haben Sie immer einen guten Ort, um alles zu validieren. Wenn Sie beispielsweise ein Objekt für die Postleitzahl erstellen und später feststellen, dass Sie sicherstellen müssen, dass die Postleitzahl immer die 4-stellige Nebenstelle enthält, die Sie haben perfekter Ort, um es auszudrücken.

Das ist eigentlich keine schlechte Idee. Wenn ich darüber nachdenke, bin ich mir nicht einmal sicher, ob ich sagen würde, dass es überhaupt überarbeitet wurde. Es ist einfach einfacher, in fast jeder Hinsicht damit zu arbeiten - die einzige Ausnahme ist die Verbreitung winziger Klassen, aber Java Klassen sind so leicht und einfach zu schreiben, dass dies kaum Kosten verursacht (sie können sogar generiert werden).

Es würde mich wirklich interessieren, ein gut geschriebenes Java Projekt zu sehen, in dem tatsächlich zu viele Klassen definiert waren (wo dies das Programmieren erschwerte). Ich fange an zu denken, dass es nicht möglich ist, zu viele zu haben Klassen.

5
Bill K

Ich denke, Sie müssen dieses Konzept von einem anderen Ausgangspunkt aus betrachten. Schauen Sie sich die Perspektive eines Datenbankdesigners an: Die im ersten Beispiel übergebenen Typen definieren Ihre Parameter nicht auf eindeutige Weise, geschweige denn auf nützliche Weise.

public void bookTicket(
  String name,
  String firstName,
  String film,
  int count,
  String cinema);

Zwei Parameter sind erforderlich, um den tatsächlichen Benutzer anzugeben, der Tickets bucht. Möglicherweise haben Sie zwei verschiedene Filme mit identischen Namen (z. B. Remakes). Möglicherweise haben Sie denselben Film mit unterschiedlichen Namen (z. B. Übersetzungen). Eine bestimmte Kette von Kinos hat möglicherweise unterschiedliche Zweigstellen. Wie gehen Sie also in einer Zeichenfolge und auf konsistente Weise damit um (z. B. verwenden Sie $chain ($city) oder $chain in $city Oder sogar? Etwas anderes und wie stellen Sie sicher, dass dies konsistent verwendet wird. Das Schlimmste ist, dass Sie Ihren Benutzer anhand von zwei Parametern angeben. Die Tatsache, dass sowohl ein Vor- als auch ein Nachname angegeben werden, garantiert keinen gültigen Kunden (und Sie können dies nicht unterscheiden Sie zwei John Doe s).

Die Antwort darauf ist, Typen zu deklarieren, aber dies sind selten dünne Wrapper, wie ich oben zeige. Höchstwahrscheinlich fungieren sie als Datenspeicher oder sind mit einer Art Datenbank gekoppelt. Ein Cinema Objekt hat also wahrscheinlich einen Namen, einen Ort, ... und auf diese Weise werden solche Unklarheiten beseitigt. Wenn es sich um dünne Umhüllungen handelt, sind sie zufällig.

Meiner Meinung nach sagt der Blog-Beitrag nur "Stellen Sie sicher, dass Sie die richtigen Typen übergeben". Der Autor hat gerade die übermäßig eingeschränkte Auswahl getroffen, um insbesondere grundlegende Datentypen auszuwählen (was die falsche Nachricht ist).

Die vorgeschlagene Alternative ist besser:

public void bookTicket(
  Name name,
  FirstName firstName,
  Film film,
  Count count,
  Cinema cinema);

Andererseits denke ich, dass der Blog-Beitrag zu weit geht, wenn man alles einpackt. Count ist zu allgemein, ich könnte Äpfel oder Orangen damit zählen, sie hinzufügen und trotzdem eine Situation in meinen Händen haben, in der das Typsystem es mir erlaubt, unsinnige Operationen durchzuführen. Sie können natürlich die gleiche Logik wie im Blog anwenden und Typen CountOfOranges usw. definieren, aber das ist auch einfach albern.

Für das, was es wert ist, würde ich tatsächlich so etwas schreiben

public Ticket bookTicket(
  Person patron,
  Film film,
  int numberOfTickets,
  Cinema cinema);

Lange Rede, kurzer Sinn: Sie sollten keine unsinnigen Variablen übergeben. Das einzige Mal, dass Sie tatsächlich ein Objekt mit einem Wert angeben, der das tatsächliche Objekt nicht bestimmt, ist, wenn Sie entweder eine Abfrage ausführen (z. B. public Collection<Film> findFilmsWithTitle(String title)) oder wenn Sie einen Proof-of- Konzept. Halten Sie Ihr Typensystem sauber, verwenden Sie also keinen Typ, der zu allgemein (z. B. ein Film, der durch ein String dargestellt wird) oder zu restriktiv/spezifisch/erfunden (z. B. Count) ist int). Verwenden Sie einen Typ, der Ihr Objekt eindeutig und eindeutig definiert, wann immer dies möglich und möglich ist.

edit: eine noch kürzere Zusammenfassung. Für kleine Anwendungen (z. B. Proof of Concepts): Warum sich mit einem komplizierten Design beschäftigen? Verwenden Sie einfach String oder int und fahren Sie fort.

Für große Anwendungen: Ist es wirklich so wahrscheinlich, dass Sie viele Klassen haben, die aus einem einzelnen Feld mit einem Basisdatentyp bestehen? Wenn Sie wenig solche Klassen haben, haben Sie nur "normale" Objekte, nichts Besonderes ist dort los.

Ich bin der Meinung, dass die Idee, Zeichenfolgen zu kapseln, ... nur ein unvollständiges Design ist: Für kleine Anwendungen zu kompliziert, für große Anwendungen nicht vollständig genug.

3
Egon

Für mich ist dies dasselbe wie die Verwendung von Regionen in C #. Wenn Sie der Meinung sind, dass dies erforderlich ist, um Ihren Code lesbar zu machen, haben Sie im Allgemeinen größere Probleme, für die Sie Ihre Zeit aufwenden sollten.

2
Tom Squires

Ich würde sagen, es ist eine wirklich gute Idee in einer Sprache mit einer stark typisierten typedef-ähnlichen Funktion.

In Java haben Sie dies nicht. Wenn Sie also eine ganz neue Klasse für diese Dinge erstellen, überwiegen die Kosten wahrscheinlich den Nutzen. Sie können auch 80% des Nutzens erzielen, indem Sie vorsichtig mit Ihrer Variablen/Ihrem Parameter umgehen Benennung.

2
jk.

Es wäre gut, wenn der String (end Integer und ... nur über String) nicht endgültig wäre, so dass diese Klassen ein (eingeschränkter) String mit Bedeutung sein und dennoch an ein unabhängiges Objekt gesendet werden könnten, das weiß, wie man damit umgeht der Basistyp (ohne sich hin und her zu unterhalten).

Und "goodnes" davon nehmen zu, wenn es z. Einschränkungen für alle Namen.

Beim Erstellen einer App (nicht einer Bibliothek) ist es jedoch immer möglich, diese umzugestalten. Also beginne ich lieber ohne.

0
user470365

Um ein Beispiel zu nennen: In unserem derzeit entwickelten System gibt es viele verschiedene Entitäten, die durch mehrere Arten von Bezeichnern (aufgrund der Verwendung externer Systeme) identifiziert werden können, manchmal sogar durch dieselbe Art von Entitäten. Alle Bezeichner sind Zeichenfolgen. Wenn also jemand verwechselt, welche Art von ID als Parameter übergeben werden soll, wird kein Fehler bei der Kompilierung angezeigt, aber das Programm wird zur Laufzeit gesprengt. Das passiert ziemlich oft. Ich muss also sagen, dass der Hauptzweck dieses Prinzips nicht darin besteht, sich vor Veränderungen zu schützen (obwohl dies auch dazu dient), sondern uns vor Fehlern zu schützen. Wenn jemand eine API entwirft, muss sie die Konzepte der Domäne widerspiegeln. Daher ist es konzeptionell nützlich, domänenspezifische Klassen zu definieren. Alles hängt davon ab, ob die Entwickler Ordnung haben, und dies kann sehr wichtig sein erleichtert durch das Typensystem!

0
thSoft