Gibt es eine allgemeine String-Substitutionsfunktion ähnlich wie sl4fj?

83

Wenn ich mit sl4fj eine String-Nachricht erstellen möchte, gibt es einen guten Ansatz, bei dem Substitutionen verwendet werden. Zum Beispiel könnte es so etwas sein wie:

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

Wenn mehr als ein paar Substitutionen erforderlich sind, ist es ungefähr so:

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

Meine Frage ist: Gibt es eine generische Möglichkeit für mich, eine Zeichenfolge zu erstellen (und nicht nur eine slf4j-Protokollnachricht)? Etwas wie:

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

oder

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

Wenn es sich in der Standard-Java-Bibliothek befindet, was wäre diese "someMethod"?

kmccoy
quelle
1
Vielen Dank an diejenigen mit Antworten unten. Außerdem stellte ich fest, dass diese Frage bereits hier gestellt wurde: stackoverflow.com/questions/3114021 . Es tut uns leid, ein mehr oder weniger Duplikat veröffentlicht zu haben.
kmccoy

Antworten:

109

String.format

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

Oder

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

Sie können auch numerische Positionen verwenden, um beispielsweise die Parameter umzuschalten:

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

Sie können String.format oder MessageFormat.format verwenden

Z.B,

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

oder einfach

MessageFormat.format("A sample value {1} with a sample string {0}", "first", 1);
Johan Sjöberg
quelle
1
MessageFormat ist sehr vielseitig und leistungsstark, aber für einfache Ersetzungen ist String.format wahrscheinlich einfacher und weniger eingeschränkt (z. B. erfordert MessageFormat, dass einfache Anführungszeichen verdoppelt werden).
Kat
1
Die neue Ganzzahl (1), die oben durch nur 1 ersetzt wurde, funktioniert ebenfalls.
TechnoCrat
25

Wenn Sie nach einer Lösung suchen, bei der Sie eine Reihe von Variablen in einem String durch Werte ersetzen können, können Sie StrSubstitutor verwenden .

 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);

Es folgt einem allgemein akzeptierten Muster, bei dem eine Karte mit Variablen zusammen mit dem nicht aufgelösten String an Werte übergeben werden kann und ein aufgelöster String zurückgegeben wird.

Balamurugan Muthiah
quelle
20

Ich würde vorschlagen, org.slf4j.helpers.MessageFormatter zu verwenden . Mit seiner Hilfe kann eine Utillity-Methode erstellt werden, die genau den gleichen Formatierungsstil wie slf4j verwendet:

// 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); 
}

Hinweis : Wenn das letzte Objekt im Array eine Ausnahme ist, wird es nicht wie bei einem slf4j-Logger in der Nachricht ersetzt. Die Ausnahme wäre über zugänglich MessageFormatter.arrayFormat(msg, objs).getThrowable().

Pete
quelle
3
Ich würde behaupten, dass dies keine gute allgemeine Antwort ist, aber tatsächlich ziemlich bis zu dem Punkt, an dem gefragt wurde.
Michael Piefel
3
Ich finde das genau die richtige Antwort. Dies sollte die beste Leistung sein.
Sasa
1
Beste Antwort, da die genaue Syntax verwendet wird, nach der die Frage gestellt wurde.
Christoph
Ehrlich gesagt, IMHO ist dies die einzige Antwort, die tatsächlich der ursprünglichen Frage entspricht ... schlägt mich, warum sie gerade auf dem vierten Platz steht ...
Raner
0

Ich wähle Wrap the Log4j2 ParameterizedMessage, die ursprünglich von Joern Huxhorn für Lilith geschrieben wurde:

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

Im Gegensatz zu SLF4J MessageFormatter, das eine unnötige Verarbeitung von Throwable enthält, liegt der Schwerpunkt auf dem Nachrichtenformat .

Siehe den Javadoc:

Verarbeitet Nachrichten, die aus einer Formatzeichenfolge bestehen, die '{}' enthält, um jedes austauschbare Token und die Parameter darzustellen.

Zhouji
quelle