Was sind die Vor- und Nachteile eines CaseInsensitiveString-Typs in Java? [geschlossen]

8

Ich bin versucht, eine zu erstellen final class CaseInsensitiveString implements CharSequence.

Dies würde es uns ermöglichen, Variablen und Felder dieses Typs zu definieren, anstatt eine reguläre zu verwenden String. Wir können auch zB a Map<CaseInsensitiveString, ?>, a Set<CaseInsensitiveString>usw. haben.

Was sind einige der Vor- und Nachteile dieses Ansatzes?

Polygenschmierstoffe
quelle
Mögliche Bedenken: Platzbedarf, Internierungsbedarf, Leistung, Müllabfuhr usw.
Polygenschmierstoffe

Antworten:

26

Groß- und Kleinschreibung ist eine Eigenschaft des Vergleichs, nicht des Objekts (*). Sie möchten dieselbe Zeichenfolge unabhängig vom Fall vergleichen oder nicht, je nach Kontext.

(Und Sie haben eine ganze Art von Würmern, da ein Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung von der Sprache abhängt - ich bin in türkischer Sprache als İ in Großbuchstaben geschrieben - und sogar der Kontext - abhängig vom Wort und dem Dialekt ß kann in Großbuchstaben geschrieben werden SS oder SZ auf Deutsch.)

(*) Es kann eine Eigenschaft des Objekts sein, das die Zeichenfolge enthält, aber das ist etwas anders als eine Eigenschaft der Zeichenfolge selbst. Und Sie können eine Klasse haben, die außer einer Zeichenfolge keinen Status hat. Wenn Sie zwei Instanzen dieser Klasse vergleichen, wird ein Vergleich der Zeichenfolge ohne Berücksichtigung der Groß- und Kleinschreibung verwendet. Diese Klasse ist jedoch keine Allzweckzeichenfolge, da sie keine Methoden bereitstellt, die für Allzweckzeichenfolgen erwartet werden, und Methoden bereitstellt, die dies nicht sind. Diese Klasse heißt nicht CaseInsensitiveString, sondern PascalIdentifier oder was auch immer zur Beschreibung relevant ist. Übrigens wird der fallunabhängige Vergleichsalgorithmus höchstwahrscheinlich durch seinen Zweck bereitgestellt und ist vom Gebietsschema unabhängig.

Ein Programmierer
quelle
1
Würden Sie eine TreeSet<String>Verwendung String.CASE_INSENSITIVE_ORDERüber a empfehlen HashSet<CaseInsensitiveString>? Beachten Sie, dass mit TreeSetMitteln O(log n)für contains. Darüber hinaus ist dieser Komparator unvereinbar mit equals, was bedeutet , dass die resultierende TreeSetnicht den allgemeinen gehorcht SetVertrag (dh kann es contains(x), auch wenn es kein Element hat , das ist equalszu x).
Polygenelubricants
Seit Mitte der 90er Jahre verwenden die von mir entworfenen generischen Hash-Tabellen sowohl eine Hash-Funktion als auch eine Gleichheitsfunktion als generische Parameter, wobei ein Standard vom Schlüsseltyp abgeleitet wird. (Wenn dies bei den von der Java-Bibliothek bereitgestellten nicht der Fall ist, riskiere ich die Erklärung, dass sie von jemandem entworfen wurden, der mit der OO-Programmierung besser vertraut ist als mit der generischen Programmierung. Sie müssen den Typ mit diesen Operationen stark eingeben in OOP aber ein Codegeruch in GP).
AProgrammer
@AProgrammer Die Java-Sammlungen verwenden die equals()Implementierung für jedes Objekt. Es gibt eine Standardimplementierung, die jedes Objekt überschreiben kann. Ich glaube nicht, dass Sie den Hash definieren können, aber ich habe es nie versucht - die Tabellen haben immer gut funktioniert, ohne sich darüber Gedanken zu machen (ein Grund, warum ich Java über C ++ mag :)).
Michael K
1
@AProgrammer - Ich bin nicht einverstanden mit "Groß- und Kleinschreibung ist eine Eigenschaft des Vergleichs, nicht des Objekts" und mit dem Vorbehalt "Vielleicht das Objekt, aber nicht die Zeichenfolge". Dies mag beschreiben, wie die Dinge sind, aber die Frage betrifft eine vorgeschlagene Änderung der Dinge. In der Modulo 3-Arithmetik steht 2 für {..., -4, -1, 2, 5, 8, 11, ...}. Die Notation stellt eine Abstraktion dar, ist aber nicht dasselbe wie die Abstraktion. Warum kann 'H' nicht die Abstraktion {'h', 'H'} darstellen? Zeichen sind im Computerspeicher überhaupt nicht vorhanden - ob ein Code 'H' oder {'h', 'H'} darstellt, es ist eine Abstraktion.
Steve314
1
@ AProgrammer - im zweiten Absatz stimme ich wahrscheinlich zu. Zumindest würde dies englische Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung, türkische Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung usw. usw. implizieren. Eine Klasse mit Unterklassen oder eine i18n-Option, IOW. Und dann erhalten Sie das Problem des doppelten Versands (wie man zwei Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung mit unterschiedlichen Sprachoptionen vergleicht). Ich denke, das ist zurück zu "Eigenschaft des Vergleichs". Verdammt!
Steve314
7

Ganz oben auf meinem Kopf:

Vorteile:

  • Macht viel Code selbstdokumentierend, zB:
    • bool UserIsRegistered(CaseInsensitiveString Username)
  • Kann Vergleiche rationalisieren
  • Kann das Potenzial für Vergleichsfehler beseitigen

Nachteile:

  • Könnte Zeitverschwendung sein
    • Benutzer können reguläre Zeichenfolgen einfach in Kleinbuchstaben umwandeln, wenn sie Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung benötigen
  • Die Verwendung für Front-End-Code führt zu Problemen bei der Großschreibung
    • Wenn Sie beispielsweise CaseInsensitiveStringeinen Benutzernamen speichern, wird im Front-End-Code der Name des Benutzers als "Bob Smith" oder "BOB SMITH" angezeigt, obwohl es sinnvoll ist, Back-End-Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen.
  • Wenn Ihre Codebasis bereits reguläre Zeichenfolgen verwendet, müssen Sie zurückgehen und diese ändern oder mit Inkonsistenzen leben
Maxpm
quelle
4
Abhängig von der Implementierung muss Ihr zweiter "Cons" -Punkt nicht gültig sein. Sie können CaseInsensitiveString implementieren, um zwischen Groß- und Kleinschreibung zu speichern und lediglich die Vergleichsoperatoren zu überschreiben.
tdammers
1
@tdammers: Wenn der CaseInsensitiveString mit case gespeichert und dann der Vergleichsoperator überschrieben wird, wird der Punkt von @AProgrammer verstärkt, dass der Vergleichsoperator von dem beliebigen Zeichenfolgenobjekt entkoppelt worden sein könnte.
Rwong
3
@tdammers - einige Dinge funktionieren bereits ähnlich. Windows-Dateisysteme behalten beispielsweise die Groß- und Kleinschreibung bei, unterscheiden jedoch nicht zwischen Groß- und Kleinschreibung. Es ist kein schlechtes System, kann aber Verwirrung stiften, wenn Sie etwas "umbenennen" möchten, um den Fall zu ändern. Grundsätzlich müssen Sie manchmal immer noch zwischen Groß- und Kleinschreibung unterscheiden, um zu vermeiden, dass Sie schlecht beurteilen, ob eine Umbenennung eine echte Änderung bewirkt - und wenn es einen Sonderfall gibt, gibt es vielleicht auch andere.
Steve314
@rwong: Ich stimme zu. Das Beste wäre, wenn nötig, explizite Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung. Manchmal möchten Sie jedoch, dass sich Zeichenfolgen wie SQL-Zeichenfolgen (mit einer CI-Sortierung) verhalten, und dann die Groß- / Kleinschreibung beim Speichern beibehalten, die Groß- und Kleinschreibung beim Vergleich jedoch ignorieren, ist die beste Übereinstimmung.
tdammers
4

CaseInsensitiveString ist keine schlechte Idee, hängt von Ihrer Verwendung ab, solange Sie nicht erwarten, dass es mit String zusammenarbeitet.

Sie können einen CaseInsensitiveString in einen String konvertieren oder umgekehrt, und das ist alles, was Sie tun sollten.

Das Problem tritt auf, wenn Sie versuchen, so etwas zu tun

class CaseInsensitiveString {
  private String value;

  public boolean equals(Object o) {
    // .....
    if (o instanceof String) {
      return value.equalsIgnoreCase((String) o);
    }
  }
}

Sie sind zum Scheitern verurteilt, wenn Sie Ihr CaseInsensitiveString-Unternehmen mit einem normalen String erstellen möchten, da Sie die Symmetrie und Transitivität für equals () (und andere Verträge) verletzen.

Bitte fragen Sie sich jedoch, in welchem ​​Fall Sie diesen CaseInsensitiveString wirklich benötigen, für den String.CASE_INSENSITIVE_ORDER nicht geeignet ist. Ich wette nicht viele Fälle. Ich bin mir sicher, dass es einen Fall geben wird, der es wert ist, diese spezielle Klasse zu haben, aber fragen Sie sich zuerst.

Adrian Shum
quelle
2

Das explizite Erstellen von Typen in Ihrer Domäne / Ihrem Modell ist eine sehr gute Vorgehensweise. Wie Maxpm sagte, ist es selbstdokumentierend. Auch ein großes Plus: Menschen können (aus Versehen) keine falschen Eingaben verwenden. Das einzig Negative wäre, dass es Junior- (und sogar einige Medior-) Programmierer abschreckt.

Ivo Limmen
quelle
1

Eine CaseInsensitiveString-Klasse und ihre Helfer fügen viel Code hinzu und machen alles weniger lesbar als die String.toLoweCase () -Methode.

CaseInsensitiveString vaName1 = new CaseInsensitiveString('HeLLo');
//... a lot of lines here
CaseInsensitiveString vaName2 = new CaseInsensitiveString('Hello');
//... a lot of lines here
if (varName1.equals(varName2)) ...

ist komplexer, weniger selbstdokumentierend und weniger flexibel als

String vaName1 = 'HeLLo';
//... a lot of lines here
String vaName2 = 'Hello';
//... a lot of lines here
if (varName1.toLowerCase().equals(varName2.toLowerCase())) ...
Ando
quelle
0

Die am häufigsten verwendeten Implementierungen im Web unterscheiden zwischen Groß- und Kleinschreibung - XML, JavaScript. In Bezug auf die Leistung ist es immer am besten, für jeden Fall die am besten geeignete Funktion / Eigenschaft / das am besten geeignete Objekt zu verwenden.

Wenn Sie mit Strukturen arbeiten - XML ​​oder JS oder ähnlichem - ist die Groß- und Kleinschreibung wichtig. Mit Systembibliotheken geht es viel schneller.

Wenn Sie mit Daten in einer Datenbank arbeiten, wie oben erwähnt, wird die Datenbankindizierung für Zeichenfolgen verwendet, bei denen zwischen Groß- und Kleinschreibung unterschieden wird.

Wenn Sie Daten im laufenden Betrieb verarbeiten, ist es wichtig, die erforderlichen Umrechnungskosten für jede Zeichenfolge zu berechnen. Es ist wahrscheinlich, dass die Zeichenfolgen irgendwie verglichen oder sortiert werden sollten.

Alper TÖR
quelle