~/home of geeks

Array vs Set Lookups

· 206 Wörter · 1 Minute(n) Lesedauer

Recht häufig benötigt man Kode, der unerlaubte Zeichen aus einem String rausfiltert. Einfach zu lesen und umzusetzen ist ein Lookup-String mit den erlaubten Zeichen. Inuitiv sollten aber solche Lookups in einer Set schneller sein. Das schaue ich mir mal an.

Eine Methode soll unerlaubte Zeichen aus einem String filtern. Im folgenden Beispiel geht es um Zeichen, die in einem Dateinamen erlaubt sein sollen. Die einfache Umsetzung über einen String, der alle erlaubten Zeichen enthält, ist einfach und lesbar:

private static final String ALLOWED_FILENAME_CHARS_ARR = "abcdefghjijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.- 0123456789";

public static boolean isValidByArray(char c) {
    return ALLOWED_FILENAME_CHARS_ARR.indexOf(c) > -1;
}

Die bessere Datenstruktur für solche Lookups sollte eine Set sein:

private static final String ALLOWED_FILENAME_CHARS_ARR = "abcdefghjijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.- 0123456789";

private static final Set<Character> ALLOWED_FILENAME_CHARS_SET;

static {
    Set<Character> tmpSet = new HashSet<>();
    for (char c : ALLOWED_FILENAME_CHARS_ARR.toCharArray()) {
        tmpSet.add(c);
    }
    ALLOWED_FILENAME_CHARS_SET = Collections.unmodifiableSet(tmpSet);
}

public static boolean isValidBySet(char c) {
    return ALLOWED_FILENAME_CHARS_SET.contains(c);
}

Wie Groß ist nun der Unterschied zwischen beiden Versionen? Ein Testlauf mit verschiedenen Prüfungen zeigt folgende Laufzeiten:

10.000.000 checks arr: 150 ms
10.000.000 checks set: 68 ms
100.000.000 checks arr: 1377 ms
100.000.000 checks set: 619 ms
1.000.000.000 checks arr: 13783 ms
1.000.000.000 checks set: 6411 ms

Die Variante mit der Set erscheint durchweg etwa doppelt so schnell.