balki
balki

Reputation: 27674

Stricter String.format that does not ignore extra arguments?

Java's String.format silently ignores extra arguments passed that are not used in format string but fails if less or invalid ones are passed. Is there a way to handle the case when more arguments are passed ?

If there are more arguments than format specifiers, the extra arguments are ignored

https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object...-

private static void doStuff(Stuff stuff, String details, Object... args) {
    if(stuff.someCondition()) {
        try {
            details = String.format("Details: " + details, args);
        } catch (Exception ex) { //No Exception thrown when args are not used by
            String arguments = Arrays.stream(args)
                    .map(Objects::toString)
                    .collect(joining(";"));
            details = String.format("Details: %s Args: %s", details, arguments);
        }
    }
    stuff.process(details);
}

private static void foo() {
    Stuff stuff = new Stuff();
    doStuff(stuff, "blah blah %s ", "blah"); // No exception, works as expected
    doStuff(stuff, "blah blah %s %s", "blah"); // Fails as expected and args are printed
    doStuff(stuff, "blah blah %s", "blah", "blah"); // Silently ignores. How to handle this case?
}

Upvotes: 4

Views: 2346

Answers (1)

balki
balki

Reputation: 27674

Taking a different approach without counting or parsing for %. Not an efficient one though.

public static String safeFormat(String formatStr, Object... args) {
    List<Object> objects = Arrays.asList(args);
    // https://commons.apache.org/proper/commons-lang/javadocs/api-3.7/org/apache/commons/lang3/mutable/MutableBoolean.html
    MutableBoolean isCalled = new MutableBoolean(false);
    objects.add(new Object(){
        @Override
        public String toString() {
            isCalled.setTrue();
            return "";
        }
    });
    String result = String.format(formatStr+"%s", objects.toArray());
    if(isCalled.isFalse()) {
        throw new IllegalArgumentException("Not all arguments used by formatter");
    }

    return result;
}

Upvotes: 0

Related Questions