masking a creditcard number in java

Here you go. Clean and reusable:

/**
 * Applies the specified mask to the card number.
 *
 * @param cardNumber The card number in plain format
 * @param mask The number mask pattern. Use # to include a digit from the
 * card number at that position, use x to skip the digit at that position
 *
 * @return The masked card number
 */
public static String maskCardNumber(String cardNumber, String mask) {

    // format the number
    int index = 0;
    StringBuilder maskedNumber = new StringBuilder();
    for (int i = 0; i < mask.length(); i++) {
        char c = mask.charAt(i);
        if (c == '#') {
            maskedNumber.append(cardNumber.charAt(index));
            index++;
        } else if (c == 'x') {
            maskedNumber.append(c);
            index++;
        } else {
            maskedNumber.append(c);
        }
    }

    // return the masked number
    return maskedNumber.toString();
}

Sample Calls:

System.out.println(maskCardNumber("1234123412341234", "xxxx-xxxx-xxxx-####"));
> xxxx-xxxx-xxxx-1234

System.out.println(maskCardNumber("1234123412341234", "##xx-xxxx-xxxx-xx##"));
> 12xx-xxxx-xxxx-xx34

Good luck.


Using Apache StringUtils...

String ccNumber = "123232323767"; 

StringUtils.overlay(ccNumber, StringUtils.repeat("X", ccNumber.length()-4), 0, ccNumber.length()-4);

Here's a slightly cleaner implementation based on StringUtils, though I am not sure how it would perform in comparison to your implementations. At any rate, the 'premature optimization' comments remain very valid.

    public static String maskNumber(final String creditCardNumber) {
    final String s = creditCardNumber.replaceAll("\\D", "");

    final int start = 4;
    final int end = s.length() - 4;
    final String overlay = StringUtils.repeat(MASK_CHAR, end - start);

    return StringUtils.overlay(s, overlay, start, end);
}