Here's utility class that is capable of filling strings with placeholders and extract values of placeholders from filled strings.Placeholders are enclosed in % characters or curly braces. Each placeholder has a pattern, which matches any value, that this placeholder can hold.It's functionality assumes that string will be constructed once and used many times for filling and extracting placeholder values. In particular, this can be useful for message configuration and localization with more semantic placeholder names (instead of {0}, {1} and etc. in MessageFormat).Usage example:// mapOf creates HashMap<> from given key-value pairsMap<String, String> patterns = mapOf(name, \\w+, id, \\d+);PlaceholdedString string = new PlaceholdedString(ID: {id}, Name: {name}, patterns::get);// fill placeholdersMap<String, String> values = mapOf(name, John, id, 123);// prints ID: 123, Name: JohnSystem.out.println(string.fill(values::get));// extract placeholder values// prints {name=Lin, id=64}System.out.println(string.extract(ID: 64, Name: Lin));PlaceholdedString class:public class PlaceholdedString {    private static final String PH_NAME = [\\w\\-_]+;    public static final Pattern PLACEHOLDER_PATTERN = Pattern.compile(\\{( + PH_NAME + )}|%( + PH_NAME + )%);    @Getter    private static class Placeholder {        /**         * Key (name) of this placeholder.         */        final String key;        /**         * Pattern which matches all possible values for this placeholder.         */        final Pattern pattern;        /**         * Group index in parent placeholded string's pattern.         * Used to extract value of this placeholder from placeholded string's matcher.         */        final int group;        /**         * Index of this placeholder in parent placeholded string.         */        final int position;        public Placeholder(String key, String regex, int group, int position) {            this.key = key;            this.pattern = Pattern.compile(regex);            this.group = group;            this.position = position;        }    }    /**     * Placeholded string, as given to constructor.     */    @Getter    private final String value;    /**     * Regexp pattern which contains all placeholder's patterns.     */    @Getter    private final Pattern pattern;    /**     * List of the placeholders in this string.     */    private final List<Placeholder> placeholders = new ArrayList<>();    /**     * Creates placeholded string.     * If string contains placeholders which are not in 'placeholders' set, execption will be thrown.     * @param pattern Pattern string with placeholders.     * @param placeholders Set of available placeholder names.     */    public PlaceholdedString(@NonNull String pattern, @NonNull Set<String> placeholders) {        this(pattern, k -> placeholders.contains(k) ? .* : null);    }    /**     * Creates placeholded string.     * If string contains placeholders for which no patterns present, execption will be thrown.     * @param pattern Pattern string with placeholders.     * @param patterns Mapping from placeholder names to placeholder regexp patterns.     */    public PlaceholdedString(@NonNull String pattern, @NonNull Function<String, String> patterns) {        this.value = pattern;        StringBuilder builder = new StringBuilder(pattern.length() + 32);        Matcher m = PLACEHOLDER_PATTERN.matcher(pattern);        int i = 0;        int groupIndex = 1;        while (i < pattern.length() && m.find(i)) {            String key = m.group(1);            if (key == null) {                key = m.group(2);            }            String pt;            switch (key) {                case percent:                    pt = %;                    break;                case obracket:                    pt = Pattern.quote({);                    break;                case cbracket:                    pt = Pattern.quote(});                    break;                default:                    pt = patterns.apply(key);                    if (pt == null) {                        throw new IllegalArgumentException(Unexpected placeholder ' + key + ' in ' + pattern + ');                    }                    break;            }            this.placeholders.add(new Placeholder(key, pt, groupIndex, m.start()));            groupIndex++;            for (char c : pt.toCharArray()) {                if (c == '(') {                    groupIndex++;                }            }            int prefixLen = m.start() - i;            if (prefixLen > 0) {                builder.append(Pattern.quote(pattern.substring(i, i + prefixLen)));            }            builder.append('(').append(pt).append(')');            i = m.end();        }        if (i < pattern.length()) {            builder.append(Pattern.quote(pattern.substring(i)));        }        this.pattern = Pattern.compile(builder.toString());    }    /**     * @return true, if this string has placeholders     */    public boolean hasPlaceholders() {        return !this.placeholders.isEmpty();    }    /**     * Replaces placeholders with actual values given by function.     * Every value will be checked to match placeholder pattern (as specified in constructor).     * @param values Function, that will return placeholder value by it's key.     * @return Filled string.     */    public String fill(@NonNull Function<String, String> values) {        if (this.placeholders.isEmpty()) {            return this.value;        }        StringBuilder result = new StringBuilder(this.value.length() + 32);        int i = 0;        for (Placeholder placeholder : this.placeholders) {            int prefixLen = placeholder.getPosition() - i;            if (prefixLen > 0) {                result.append(this.value.substring(i, i + prefixLen));            }            switch (placeholder.getKey()) {                case percent:                    result.append(%);                    break;                case obracket:                    result.append({);                    break;                case cbracket:                    result.append(});                    break;                default:                    String value = values.apply(placeholder.getKey());                    if (value == null) {                        throw new IllegalArgumentException(Placeholder ' + placeholder + ' has null value);                    }                    if (!placeholder.getPattern().matcher(value).matches()) {                        throw new IllegalArgumentException(String ' + value + ' does not match  +                                pattern ' + placeholder.getPattern().pattern() + '  +                                of placeholder ' + placeholder.getKey() + '                        );                    }                    result.append(value);                    break;            }            i = placeholder.getPosition() + placeholder.getKey().length() + 2;        }        if (i < this.value.length()) {            result.append(this.value.substring(i));        }        return result.toString();    }    /**     * Extract placeholder values from specified string.     * String should match pattern used to create this object.     * Returned map may be unmodifable.     * @param s String, where placeholders were replaced with actual values.     * @return Map, where keys are placeholder keys, and values are extracted values     * or null, if given string does not match this string's pattern.     */    @Nullable    public Map<String, String> extractNullable(@NonNull String s) {        if (this.placeholders.isEmpty()) {            return s.equals(this.value) ? Collections.emptyMap() : null;        }        // fast check        if (!this.value.isEmpty()) {            char c = this.value.charAt(0);            // If first char in the pattern is not a start of placeholder:            // Then check, whether the first char of the given string == first pattern's char            // If it is not equals, then given string does not match pattern            if (c != '%' && c != '{' && (s.isEmpty() || s.charAt(0) != c)) {                return null;            }        } else {            if (!s.isEmpty()) {                return null;            } else {                return Collections.emptyMap();            }        }        Matcher m = this.pattern.matcher(s);        if (!m.matches()) {            return null;        }        Map<String, String> result = new HashMap<>((int) Math.ceil(this.placeholders.size() / 0.75D));        for (Placeholder placeholder : this.placeholders) {            result.put(placeholder.getKey(), m.group(placeholder.getGroup()));        }        return result;    }    /**     * Extract placeholder values from specified string.     * String should match pattern used to create this object.     * @param s String, where placeholder %keys% replaced with actual values.     * @return Map, where keys are placeholder keys, and values are extracted values.     */    public Map<String, String> extract(@NonNull String s) {        Map<String, String> map = extractNullable(s);        if (map == null) {            throw new IllegalArgumentException(String ' + s + ' does not match ' + this.pattern.pattern() + ');        }        return map;    }    public List<Map<String, String>> extractAll(@NonNull String s) {        if (s.isEmpty()) {            return Collections.emptyList();        }        List<Map<String, String>> result = new ArrayList<>();        Matcher m = this.pattern.matcher(s);        while (m.find()) {            Map<String, String> map = new HashMap<>();            for (Placeholder placeholder : this.placeholders) {                map.put(placeholder.getKey(), m.group(placeholder.getGroup()));            }            result.add(map);        }        return result;    }    /**     * Throw an exception, if any of specified placeholder names is not contained in this string.     * @param placeholdersRequired Names of required placeholders     * @return this string     */    public PlaceholdedString require(@NonNull String... placeholdersRequired) {        Set<String> absent = new HashSet<>(Arrays.asList(placeholdersRequired));        // remove existed placeholders        this.placeholders.forEach(p -> absent.remove(p.key));        if (absent.size() > 0) {            throw new IllegalArgumentException(String ' + this.value + ' requires placeholders:  + absent);        }        return this;    }}I have optimized placeholded strings which have no placeholders: if so, fill() method just returns this string, and extract() method simply checks equality of the given string and pattern string, and returns emptyMap().In my project this class is frequently used (both filling and extracting features), and good performance matters. How can I improve performance?Also, looking for feedback about code style (methods & fields naming and order, code format, etc.).
Named placeholders filling and extraction in Java
java;regex;formatting