In der Softwareentwicklung gibt es oft Szenarien, in denen sensible Daten wie Passwörter, Kreditkartennummern oder andere persönliche Informationen teilweise maskiert werden müssen. Dabei bleibt oft ein Teil der Zeichen (z. B. die letzten vier Ziffern) unmaskiert, während der Rest durch Sternchen oder andere Platzhalter ersetzt wird. In diesem Artikel werden verschiedene Ansätze vorgestellt, wie man solche Maskierungen in Java umsetzen kann. Dabei wird sowohl auf Methoden eingegangen, die mit Java 8 kompatibel sind, als auch auf Lösungen, die Funktionen ab Java 17 nutzen.

Grundlagen und Anforderungen

Die Aufgabe besteht darin, einen String so zu maskieren, dass:

  1. Der Anfangsteil des Strings durch ein bestimmtes Zeichen (z. B. *) ersetzt wird.
  2. Die letzten n Zeichen unmaskiert bleiben.

Beispiel: Aus dem String 1234567890 soll bei einer Maskierung mit Sternchen und n = 4 der String ******7890 entstehen.

Maskierungsmethoden in Java 8

Java 8 bietet grundlegende Funktionen, mit denen diese Aufgabe bewältigt werden kann, wie StringBuilder, Schleifen oder reguläre Ausdrücke. Diese Methoden sind zwar nicht immer die kürzesten, aber effektiv und vielseitig einsetzbar.

1. Nutzung von StringBuilder

Mit einem StringBuilder lässt sich die Maskierung manuell umsetzen:

public static String maskString(String input, int unmaskedLength) {
    if (input == null || input.length() <= unmaskedLength) {
        return input;
    }
    int maskedLength = input.length() - unmaskedLength;
    StringBuilder maskedString = new StringBuilder();
    for (int i = 0; i < maskedLength; i++) {
        maskedString.append("*");
    }
    maskedString.append(input.substring(maskedLength));
    return maskedString.toString();
}
Code-Sprache: JavaScript (javascript)

Erläuterung:

  • Es wird zuerst die Länge der zu maskierenden Zeichen berechnet.
  • Eine Schleife füllt den StringBuilder mit Sternchen.
  • Der unmaskierte Teil wird anschließend angefügt.

2. Verwendung von String.repeat() (Optional in Java 11 eingeführt)

Wer Java 11 verwendet, kann den Code mit der Methode String.repeat() vereinfachen:

public static String maskString(String input, int unmaskedLength) {
    if (input == null || input.length() <= unmaskedLength) {
        return input;
    }
    int maskedLength = input.length() - unmaskedLength;
    return "*".repeat(maskedLength) + input.substring(maskedLength);
}
Code-Sprache: JavaScript (javascript)

3. Einsatz von regulären Ausdrücken

Mit regulären Ausdrücken kann die Maskierung ebenfalls elegant gelöst werden:

public static String maskString(String input, int unmaskedLength) {
    if (input == null || input.length() <= unmaskedLength) {
        return input;
    }
    int maskedLength = input.length() - unmaskedLength;
    return input.replaceAll(".{" + maskedLength + "}(?=.{" + unmaskedLength + "}$)", "*");
}
Code-Sprache: JavaScript (javascript)

Erläuterung:

  • Der reguläre Ausdruck sucht nach den ersten maskedLength Zeichen und ersetzt diese durch Sternchen.
  • (?=...) ist ein Lookahead, der sicherstellt, dass die letzten unmaskedLength Zeichen unberührt bleiben.

Verbesserte Ansätze ab Java 17

Java 17 bringt Features wie Pattern-Matching für switch und Verbesserungen im Bereich String-Handling. Diese können genutzt werden, um den Code weiter zu vereinfachen oder lesbarer zu gestalten.

1. Verwendung von Text Blocks

Mit Textblöcken können reguläre Ausdrücke übersichtlicher gestaltet werden:

public static String maskString(String input, int unmaskedLength) {
    if (input == null || input.length() <= unmaskedLength) {
        return input;
    }
    int maskedLength = input.length() - unmaskedLength;
    String regex = """
        .{""" + maskedLength + """}(?=.{""" + unmaskedLength + """}$)
        """;
    return input.replaceAll(regex, "*");
}
Code-Sprache: PHP (php)

2. Nutzung von Pattern und Matcher

Ab Java 17 kann die Pattern-Klasse mit erweiterten Features kombiniert werden, um reguläre Ausdrücke effizient zu handhaben:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public static String maskString(String input, int unmaskedLength) {
    if (input == null || input.length() <= unmaskedLength) {
        return input;
    }
    int maskedLength = input.length() - unmaskedLength;
    Pattern pattern = Pattern.compile(".{" + maskedLength + "}(?=.{" + unmaskedLength + "}$)");
    Matcher matcher = pattern.matcher(input);
    return matcher.replaceAll("*");
}
Code-Sprache: JavaScript (javascript)

Erläuterung:

  • Pattern und Matcher erlauben es, reguläre Ausdrücke effizient zu erstellen und mehrfach wiederzuverwenden.

Performance-Vergleich

Die Performance der verschiedenen Ansätze hängt stark von der String-Länge und der verwendeten Methode ab. Einige Beobachtungen:

  1. StringBuilder ist bei kurzen Strings oft am schnellsten, da er minimalen Overhead hat.
  2. Reguläre Ausdrücke können bei langen Strings effizient sein, aber sind etwas langsamer bei kleinen Datenmengen.
  3. String.repeat() bietet eine gute Balance zwischen Lesbarkeit und Performance, sofern Java 11+ verwendet wird.

Fazit

Die Wahl der Methode hängt von der Java-Version, dem Kontext und den persönlichen Vorlieben ab. In Java 8 sind StringBuilder und reguläre Ausdrücke die wichtigsten Werkzeuge. Ab Java 17 können moderne Features wie Text Blocks oder optimierte Regex-Verarbeitung den Code eleganter und lesbarer machen. Entwicklern steht somit eine breite Palette an Lösungen zur Verfügung, um die Maskierung effizient und flexibel umzusetzen.