有没有类似于 sl4fj 的通用字符串替换函数?

使用 sl4fj,如果我想构造一个字符串消息,那么有一种很好的方法可以利用替换。例如,它可能是这样的:

logger.info("Action {} occured on object {}.", objectA.getAction(), objectB);

如果需要更多的替换,则类似于:

logger.info("Action {} occured on object {} with outcome {}.",
new Object[]{objectA.getAction(), objectB, outcome});

我的问题是: 是否有创建字符串(而不仅仅是 slf4j 日志消息)的通用方法?比如:

String str = someMethod("Action {} occured on object {}.", objectA.getAction(), objectB);

或者

String str = someMethod("Action {} occured on object {} with outcome {}.",
new Object[]{objectA.getAction(), objectB, outcome});

如果它在标准 Java 库中,那么“ some Method”是什么呢?

93316 次浏览

You can use String.format or MessageFormat.format

E.g.,

MessageFormat.format("A sample value {1} with a sample string {0}",
new Object[] {"first", 1});

or simply

MessageFormat.format("A sample value {1} with a sample string {0}", "first", 1);

String.format

String str = String.format("Action %s occured on object %s.",
objectA.getAction(), objectB);

Or

String str = String.format("Action %s occured on object %s with outcome %s.",
new Object[]{objectA.getAction(), objectB, outcome});

You can also use numeric positions, for example to switch the parameters around:

String str = String.format("Action %2$s occured on object %1$s.",
objectA.getAction(), objectB);

If you are looking for a solution where you can replace a bunch of variables in a String with values, you can use StrSubstitutor.

 Map<String, String> valuesMap = new HashMap<>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StrSubstitutor sub = new StrSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);

It follows a generally accepted pattern where one can pass a map with variables to values along with the unresolved String and it returns a resolved String.

I would suggest to use org.slf4j.helpers.MessageFormatter. With the help of it one can create a utillity method that uses the exact same formatting style as slf4j:

// utillity method to format like slf4j
public static String format(String msg, Object... objs) {
return MessageFormatter.arrayFormat(msg, objs).getMessage();
}


// example usage
public static void main(String[] args) {
String msg = format("This msg is {} like slf{}j would do. {}", "formatted", 4,
new Exception("Not substituted into the message"));


// prints "This msg is formatted like slf4j would do. {}"
System.out.println(msg);
}

Note: If the last object in the array is an Exception it will not be substituted in the message, just like with an slf4j logger. The Exception would be accessible via MessageFormatter.arrayFormat(msg, objs).getThrowable().

I choose wrap the Log4j2 ParameterizedMessage which was originally written for Lilith by Joern Huxhorn:

public static String format(final String messagePattern, Object... arguments) {
return ParameterizedMessage.format(messagePattern, arguments);
}

It is focus on message format, unlike SLF4J MessageFormatter which contains unnecessary processing of Throwable.

See the Javadoc:

Handles messages that consist of a format string containing '{}' to represent each replaceable token, and the parameters.