Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Java ist auch eine Insel von Christian Ullenboom
Buch: Java ist auch eine Insel (Galileo Computing)
gp Kapitel 4 Der Umgang mit Zeichenketten
gp 4.1 Strings und deren Anwendung
gp 4.1.1 String-Objekte für konstante Zeichenketten
gp 4.1.2 String-Länge
gp 4.1.3 Gut, dass wir verglichen haben
gp 4.1.4 String-Teile extrahieren
gp 4.1.5 Suchen und Ersetzen
gp 4.1.6 Veränderte Strings liefern
gp 4.1.7 Typen in Zeichenketten konvertieren
gp 4.2 Veränderbare Zeichenketten mit der Klasse StringBuffer
gp 4.2.1 Anlegen von StringBuffer-Objekten
gp 4.2.2 Die Länge eines StringBuffer-Objekts lesen und setzen
gp 4.2.3 Daten anhängen
gp 4.2.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen
gp 4.3 Vergleiche von Zeichenketten
gp 4.3.1 equals() in String und StringBuffer
gp 4.3.2 Sollte es ein equals() und hash() bei StringBuffer geben?
gp 4.3.3 Sprachabhängiges Vergleichen mit der Collator-Klasse
gp 4.3.4 Effiziente interne Speicherung für die Sortierung
gp 4.4 Zeichenkodierungen umwandeln
gp 4.5 Die Klasse StringTokenizer
gp 4.6 Der BreakIterator als Wort- und Satztrenner
gp 4.7 Formatieren mit Format-Objekten
gp 4.7.1 Prozente, Zahlen und Währungen ausgeben
gp 4.7.2 Ausgaben formatieren
gp 4.7.3 Dezimalzahlformatierung
gp 4.8 Reguläre Ausdrücke
gp 4.8.1 Splitten von Zeichenketten
gp 4.8.2 split() in String
gp 4.8.3 Das alternative Paket org.apache.regexp


Galileo Computing

4.3 Vergleiche von Zeichenkettendowntop


Galileo Computing

4.3.1 equals() in String und StringBufferdowntop

Ein Blick in die API-Dokumentation der Klasse String zeigt eine equals()-Methode, mit der Zeichenketten vom Typ String verglichen werden können. Leider vergleicht die Methode nur String/String-Paare, aber keine String/StringBuffer-Paare. Das bedeutet, einen String mit einem StringBuffer zu vergleichen führt zwar bei equals() nicht zu einem Compilerfehler (da equals(Object) alles entgegennimmt), aber auch zu nichts Sinnvollem, da der Vergleich immer false ist. Denn die Implementierung testet, ob das an equals() übergebene Parameterobjekt instanceof String ist. Uns bleibt daher nichts anderes übrig, als bei einem StringBuffer den Vergleich auf String-Ebene durchzuführen.

In der Version 1.4 der Java-Standardbibliothek hat sich das jedoch mit der String-Funktion contentEquals(StringBuffer) geändert. Die Methode liefert true, wenn der StringBuffer und der betrachtende String den gleichen Zeicheninhalt haben. Die interne Länge spielt keine Rolle. Ist sb=null, wird eine NullPointerException ausgelöst.


Beispiel Vergleiche einen String mit einem StringBuffer:
String s = "Elektrisch-Zahnbürster";
StringBuffer sb = new StringBuffer( "Elektrisch-Zahnbürster" );
boolean b1 = s.equals( sb );                 // false
boolean b1 = s.equals( sb.toString() );      // true

Wollen wir zwei StringBuffer-Objekte miteinander vergleichen, werden wir noch mehr enttäuscht. Die Klasse StringBuffer definiert überhaupt keine eigene equals()-Methode. Es gibt zwar eine, doch die wird von der Klasse Object geerbt, und das heißt, nur Objektreferenzen werden verglichen. Wenn also zwei verschiedene StringBuffer-Objekte mit gleichem Inhalt mit equals() verglichen werden, kommt trotzdem immer false heraus.


Beispiel Um den inhaltlichen Vergleich von zwei StringBuffer-Objekten zu realisieren, müssen wir diese erst mit toString() in Strings umwandeln.
StringBuffer sb1 = new StringBuffer( "Saftpresse" );
StringBuffer sb2 = new StringBuffer( "Saftpresse" );
boolean b1 = sb1.equals( sb2 );                     // false
boolean b2 = sb1.toString().equals(sb2.toString()); // true


Galileo Computing

4.3.2 Sollte es ein equals() und hash() bei StringBuffer geben?downtop

Die obige Betrachtung zeigt, dass eine Methode equals(), welche den Inhalt von StringBuffer-Objekten vergleicht, nicht schlecht wäre. Dennoch besteht das Problem, wann StringBuffer-Objekte als gleich angesehen werden sollen. Das ist interessant, denn StringBuffer-Objekte sind nicht nur durch ihren Inhalt bestimmt, sondern auch durch die Größe ihres internen Puffers, ihre Kapazität. Sollte equals() den Rückgabewert true haben, wenn die Inhalte gleich sind oder nur wenn Inhalt und Puffergröße gleich sind? Da jeder Entwickler andere Ansichten über die Gleichheit besitzt, bleibt es bei dem standardmäßigen Test auf identische Objektreferenzen.

hashCode()

Eine hashCode()-Methode liefert für alle inhaltsgleichen Objekte denselben, im Idealfall eindeutigen Zahlenwert, der hilft, diese Objekte von davon verschiedenen Objekten zu unterscheiden. Dieser Zahlenwert wird bei Zeichenketten etwa wie folgt gebildet:

hash = 0;
for ( int i = 0; i < s.length(); i++ )
  hash = 31*hash + s.charAt(i);

Die Klasse String besitzt eine hashCode()-Methode, wie oben gezeigt. StringBuffer erbt die Implementierung aus der Klasse Object unverändert. Die Klasse selbst bietet keine Implementierung an - bei der hashCode()-Methode aus dem gleichen Grund wie bei equals().


Galileo Computing

4.3.3 Sprachabhängiges Vergleichen mit der Collator-Klassedowntop

Mit der Collator-Klasse ist es möglich, Zeichenketten nach jeweils landesüblichen Kriterien zu vergleichen. So werden die Sprachbesonderheiten jedes Landes beachtet.


Beispiel Für die deutsche Sprache gilt, dass »ä« zwischen »a« und »b« äquivalent zu »ae« einsortiert wird und nicht so, wie der ASCII-Zeichensatz das Zeichen einordnet, hinter dem »z«. Ähnliches gilt für das »ß«. Auch das Spanische hat seine Besonderheiten im Alphabet. Hier gelten das »ch« und das »ll« als einzelner Buchstabe.

Ein Collator-Objekt wird vor seiner Benutzung mit getInstance() erzeugt. Dieser Funktion kann auch ein Argument übergeben werden, mit dem der jeweils gewünschte Ländercode ausgewählt werden kann: getInstance(Locale.GERMAN) ermöglicht richtiges Vergleichen für deutsche Zeichenketten. Die Länderbezeichnungen sind Konstanten aus der Locale-Klasse.


abstract class java.text.Collator
implements Comparator, Cloneable

gp static Collator getInstance()
gp Liefert einen Collator für die aktuelle Landessprache.
gp static Collator getInstance( Locale desiredLocale )
gp Liefert einen Collator für die gewünschte Sprache.
gp abstract int compare( String source, String target )
gp Vergleicht die beiden Zeichenketten auf ihre Ordnung. Der Rückgabewert ist entweder <0, 0 oder >0.
gp int compare( Object o1, Object o2 )
gp Vergleicht die beiden Argumente auf ihre Ordnung. Ruft compare((String)o1, (String)o2) auf.

Listing 4.2 CollatorDemo.java

import java.util.*;
import java.text.*;
class CollatorDemo
{
  public static void comp( Collator col, String a, String b )
  {
    if ( col.compare( a, b ) < 0 )
      System.out.println( a+" < "+b );
    if ( col.compare( a, b ) == 0 )
      System.out.println( a+" = "+b );
    if ( col.compare( a, b ) > 0 )
      System.out.println( a+" > "+b );
  }
  public static void main( String args[] )
  {
    Collator col = Collator.getInstance( Locale.GERMAN );
    System.out.println( "Strength = PRIMARY" );
    col.setStrength( Collator.PRIMARY );
    comp( col, "abc", "ABC" );
    comp( col, "Quäken", "Quaken" );
    comp( col, "boß", "boss" );
    comp( col, "boß", "boxen" );
    System.out.println( "\nStrength =  SECONDARY" );
    col.setStrength( Collator.SECONDARY );
    comp( col, "abc", "ABC" );
    comp( col, "Quäken", "Quaken" );
    comp( col, "boß", "boss" );
    comp( col, "boß", "boxen" );
    System.out.println( "\nStrength =  TERTIARY" );
    col.setStrength( Collator.TERTIARY );
    comp( col, "abc", "ABC" );
    comp( col, "Quäken", "Quaken" );
    comp( col, "boß", "boss" );
    comp( col, "boß", "boxen" );
  }
}

Die Ausgabe1 ist Folgende:

Strength = PRIMARY
abc = ABC
Quäken = Quaken
boß = boss
boß < boxen
Strength =  SECONDARY
abc = ABC
Quäken > Quaken
boß = boss
boß < boxen
Strength =  TERTIARY
abc < ABC
Quäken > Quaken
boß > boss
boß < boxen

Die Collator-Klasse besitzt viele sinnvolle Methoden, die über die Vergleichsfunktionalität der String- und StringBuffer-Klasse hinausgehen. So ist es über die Funktion setStrength() möglich, die Toleranz bei Vergleichen einzustellen. Beispielsweise erkennt der tolerante Vergleich »abc« und »ABC« als gleich.


Galileo Computing

4.3.4 Effiziente interne Speicherung für die Sortierungtoptop

Obwohl sich mit der Collator-Klasse sprachspezifische Vergleiche korrekt umsetzen lassen, ist die Geschwindigkeit gegenüber einem normalen String-Vergleich geringer. Daher bietet die Collator-Klasse die Objektmethode getCollationKey() an, die ein CollationKey-Objekt liefert, das schnellere Vergleiche zulässt.

Collator col = Collator.getInstance( Locale.GERMAN );
CollationKey key1 = col.getCollationKey( "ätzend" );
CollationKey key2 = col.getCollationKey( "Bremsspur" );

Durch CollationKeys lässt sich die Performance bei Vergleichen zusätzlich verbessern, da der landesspezifische String in einen dazu passenden, normalen Java-String umgewandelt wird, der dann schneller gemäß der internen Unicode-Zeichenkodierung verglichen werden kann. Dies bietet sich zum Beispiel beim Sortieren einer Tabelle an, wo mehrere Vergleiche mit dem gleichen String durchgeführt werden müssen. Der Vergleich wird mit compareTo(CollationKey) durchgeführt.


Beispiel Der Vergleich von key1 und key2 lässt sich durch folgende Zeile ausdrücken.
int comp = key2.compareTo( key1 );

Das Ergebnis ist wie bei der compare()-Methode bei Collator-Objekten entweder <0, 0 oder >0.



class java.text.CollationKey
implements Comparable

gp int compareTo( CollationKey target )
Vergleicht zwei CollationKey-Objekte miteinander.
gp int compareTo( Object o )
Vergleicht den aktuellen CollationKey mit dem angegebenen Objekt.
gp Ruft compareTo( (CollationKey)o ) auf.
gp boolean equals( Object target )
Testet die beiden CollationKey-Objekte auf Gleichheit.
gp String getSourceString()
Liefert den String zum CollationKey.
gp int hashCode()
Berechnet den Hashcode für den CollationKey.
gp byte[] toByteArray()
Konvertiert den CollationKey in eine Folge von Bytes.

abstract class java.text.Collator
implements Comparator, Cloneable

gp abstract CollationKey getCollationKey( String source )
gp Liefert einen CollationKey für den konkreten String.





1 Erstaunlicherweise ergibt sich unter einigen Linux-Versionen ein etwas anderes Bild, denn die Sortierreihenfolge ist dort durch einen Bug falsch.





Copyright (c) Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de