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 erscheint aber eine Set zu 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:

10000000 checks arr: 150 ms
10000000 checks set: 68 ms
100000000 checks arr: 1377 ms
100000000 checks set: 619 ms
1000000000 checks arr: 13783 ms
1000000000 checks set: 6411 ms

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