Java Effiziente String Algorithmen

Effiziente String Algorithmen

Die vielen Möglichkeiten, in Java mit Strings zu operieren, bieten leider auch viele Chancen, dies sehr ineffizient zu tun.
Hier sind ein paar Beispiele zusammengefasst, wie man häufig benötigte String-Operationen effizient implementieren kann.

Vorrat an Zeichenketten halten

Wenn man häufig String oder besser StringBuffer Objekte mit einer unterschiedlichen Anzahl gleicher Zeichen auffüllen möchte, so hält man sich dafür ggf gerne einen Vorrat.
In diesem Beispiel halten wir uns einen Vorrat von Leerzeichen.
Etwas anderes, wie zum Beispiel führende Nullen, wären genauso denkbar.

Der Trick:
Anstatt die unterschiedlich langen Zeichenketten häufig anzulegen, erzeugen wir zwar 101 String Objekte, die aber alle auf das gleiche interne char-Array zurückgreifen.


    private static final String[] BUFFER;
    static {
        final String LONGEST_BUFFER = "                                                                                                    ";
        final int MAX_BUFFER = LONGEST_BUFFER.length();
        BUFFER = new String[MAX_BUFFER + 1];
        for (int i = BUFFER.length; i >= 0; i--) {
            BUFFER[i] = LONGEST_BUFFER.substring(0, i);
        }
    }

Auf den ersten Blick überraschend dürfte sein, daß es sich lohnen soll, aus einem maximalen Puffer ständig Teilstrings zu ziehen.
Aber genau das tut es, weil die String-Klasse für alle diese 101 String-Objekte intern nur ein einziges char-Array hält. Alle Strings bedienen sich eines Teils dieses Arrays.
So haben wir Speicherplatz gespart.

Zeichenketten dynamisch erzeugen

Hinweis: Dieses Codebeispiel verwendet den oben erzeugten Puffer.


public static String createSpaces(final int count) {
    if (count < BUFFER.length) {
        return BUFFER[count];
    }
    return createChain(' ', count);
}

public static String createChain(final char c, final int count) {
    final StringBuffer result = new StringBuffer(count);
    for (int i = count; i > 0; i--) {
        result.append(c);
    }
    return result.toString();
}

String mit Leerzeichen füllen

Hier ein Beispiel, wie man einen String mit Leerzeichen auf eine bestimmte Länge erweitert:
public static String toLen(final String value, final int len) {
    final int count = len - value.length();
    if (count > 0) {
        final StringBuffer result = new StringBuffer(len);
        result.append(value);
        for (int i = count; i >= 0; i--) {
            result.append(' ');
        }
        return result.toString();
    } else {
        return value;
    }
}

String mit Zahl mit führenden Nullen

Zur rechtsbündigen Formatierung füllen wir Zahlen mit führenden Nullen auf.
Genauso könnte man natürlich führende Leerzeichen verwenden:
public static String formatRight(final Object value, final int len) {
    final String valueAsString = String.valueOf(value);
    if (valueAsString.length() < len) {
        final StringBuffer result = new StringBuffer(len);
        for (int i = len - valueAsString.length(); i > 0; i--) {
            result.append('0');
        }
        result.append(valueAsString);
        return result.toString();
    } else {
        return valueAsString;
    }
}

String mit konstantem Zeichen auffüllen - mehrere Funktionen gebündelt und überladen

Zur links- oder rechtsbündigen Formatierung will man String Objekte gelegentlich mit konstanten Zeichen auffüllen, z. B. Zahlen mit führenden Nullen, oder mit führenden Leerzeichen, wenn ASCII-Text formatiert werden soll.
Genau dies leisten die folgende Methoden effizient.
Alltagsfreundlich sind die überladenen Versionen mit weniger Parametern.
public static final int NO_CUT = 0;
public static final int CUT_LEFT = 1;
public static final int CUT_RIGHT = 2;
public static String format(final String value, final char c, final int count, final boolean fillLeft, final int tooBigStringsCutStrategy) {
    if (value == null || value.length() == 0) {
        return createChain(c, count);
    }
    if (value.length() >= count) {
        if (tooBigStringsCutStrategy == CUT_LEFT) {
            return value.substring(value.length() - count);
        }
        return (tooBigStringsCutStrategy == CUT_RIGHT) ? value.substring(0, count) : value;
    }
    final StringBuffer result = new StringBuffer(count);
    if (!fillLeft) {
        result.append(value);
    }
    for (int i = value.length(); i < count; i++) {
        result.append(c);
    }
    if (fillLeft) {
        result.append(value);
    }
    return result.toString();
}

public static String format(final String value, final char c, final int count, final boolean fillLeft) {
    return format(value, c, count, fillLeft, CUT_RIGHT);
}
public static String format(final String value, final char c, final int count) {
    return format(value, c, count, true, CUT_RIGHT);
}

Beispiele:

String mit Leerzeichen auffüllen
Um einen String rechts- oder linksbündig mit Leerzeichen aufzufüllen, rufen wir nur noch die oben implementierte format()-Funktion auf:

    String value = "Hallo";
    String valueRight = format(value, ' ', 10, true); // erzeugt "     Hallo"
    String valueLeft = format(value, ' ', 10, false); // erzeugt "Hallo     "

Zahl mit führenden Nullen
Ebenfalls auf Basis der oben implementierten format()-Funktion füllen wir Strings mit führenden Nullen auf:

    String value = "2578";
    String valueRight = format(value, '0', 7, true); // erzeugt "0002578"

Einfachere Implementierungen

Wer die gute Performance der hier vorgestellten String-Operationen gar nicht benötigt, kann diese auch deutlich einfacher implementieren. Im Artikel über möglichst einfache String-Operationen werden kurze, knackige und dafür wenig performante Implementierungen vorgestellt: Einfach implementierte String Operationen



Nach oben, Inhaltsverzeichnis, Impressum Admin: Artikel editieren