Sprintf-Äquivalent in Java

Lesezeit: 5 Minuten

Benutzer-Avatar
Papierpferd

Printf wurde mit der Version 1.5 zu Java hinzugefügt, aber ich kann anscheinend nicht finden, wie ich die Ausgabe an eine Zeichenfolge statt an eine Datei senden soll (was sprintf in C tut). Weiß jemand, wie das geht?

Benutzer-Avatar
Eugen Yokota

// Store the formatted string in 'result'
String result = String.format("%4d", i * j);

// Write the result to standard output
System.out.println( result );

Sehen Format und sein Syntax

Benutzer-Avatar
FlySwat

Strings sind unveränderliche Typen. Sie können sie nicht ändern, sondern nur neue String-Instanzen zurückgeben.

Aus diesem Grund macht die Formatierung mit einer Instanzmethode wenig Sinn, da sie wie folgt aufgerufen werden müsste:

String formatted = "%s: %s".format(key, value);

Die ursprünglichen Java-Autoren (und .NET-Autoren) entschieden, dass eine statische Methode in dieser Situation sinnvoller ist, da Sie das Ziel nicht ändern, sondern stattdessen eine Formatmethode aufrufen und eine Eingabezeichenfolge übergeben.

Hier ist ein Beispiel dafür, warum format() wäre als Instanzmethode dumm. In .NET (und wahrscheinlich in Java) Replace() ist eine Instanzmethode.

Du kannst das:

 "I Like Wine".Replace("Wine","Beer");

Es passiert jedoch nichts, da Zeichenfolgen unveränderlich sind. Replace() versucht, einen neuen String zurückzugeben, aber es ist nichts zugewiesen.

Dies verursacht viele häufige Anfängerfehler wie:

inputText.Replace(" ", "%20");

Auch hier passiert nichts, stattdessen müssen Sie Folgendes tun:

inputText = inputText.Replace(" ","%20");

Nun, wenn Sie verstehen, dass Strings unveränderlich sind, macht das absolut Sinn. Wenn nicht, dann bist du nur verwirrt. Der richtige Ort für Replace() wäre wo format() ist als statische Methode von String:

 inputText = String.Replace(inputText, " ", "%20");

Jetzt ist es keine Frage, was los ist.

Die eigentliche Frage ist, warum die Autoren dieser Frameworks entschieden haben, dass eines eine Instanzmethode und das andere eine statische sein sollte. Meiner Meinung nach werden beide als statische Methoden eleganter ausgedrückt.

Unabhängig von Ihrer Meinung ist die Wahrheit, dass Sie mit der statischen Version weniger fehleranfällig sind und der Code leichter zu verstehen ist (keine versteckten Fallstricke).

Natürlich gibt es einige Methoden, die sich perfekt als Instanzmethoden eignen, nehmen Sie String.Length()

int length = "123".Length();

In dieser Situation ist es offensichtlich, dass wir nicht versuchen, “123” zu ändern, wir untersuchen es nur und geben seine Länge zurück. Dies ist ein perfekter Kandidat für eine Instanzmethode.

Meine einfachen Regeln für Instanzmethoden auf unveränderlichen Objekten:

  • Wenn Sie eine neue Instanz desselben Typs zurückgeben müssen, verwenden Sie eine statische Methode.
  • Verwenden Sie andernfalls eine Instanzmethode.

  • Ich sehe, dass Sie irgendwie auf die Idee gekommen sind, dass ich vorschlug, dass die Formatzeichenfolge geändert werden sollte. Ich habe nie die Möglichkeit in Betracht gezogen, dass jemand erwartet, dass sich ein String ändert, da seine Unveränderlichkeit so grundlegend ist.

    – Ericsson

    13. Oktober 2008 um 18:14 Uhr

  • Da der Formatstring meistens eher “The Price is %4d” und nicht “%4d” lautet, sehe ich noch viel Verwirrungspotential. Was haben Sie gegen statische Methoden? 🙂

    – FlySwat

    13. Oktober 2008 um 18:20 Uhr

  • Diese Antwort scheint nichts mit der Frage zu tun zu haben.

    – Steve McLeod

    6. Juni 2009 um 7:58 Uhr

  • Die Antwort ist nicht einmal Java, scheint für .NET relevanter zu sein

    – Photodeus

    19. November 2009 um 6:35 Uhr

  • -1. Abgestimmt b / c, es ist tangential. Und nicht unbedingt der beste Stil für Immutables. Dieser Stil ist ausführlicher als einfache Methodenaufrufe, insbesondere für verkettete Operationen. Und es gibt den Laufzeitpolymorphismus auf, weil es statische Methoden aufruft, was von Bedeutung ist. YMMV.

    – Andreas Janke

    21. April 2014 um 3:11 Uhr

Seit Java 13 haben Sie formatted 1 -Methode auf String, die zusammen mit Textblöcken als Vorschaufunktion hinzugefügt wurde 2. Sie können es stattdessen verwenden String.format()

Assertions.assertEquals(
   "%s %d %.3f".formatted("foo", 123, 7.89),
   "foo 123 7.890"
);

Beide Lösungen simulieren printf, aber auf unterschiedliche Weise. Um beispielsweise einen Wert in einen Hex-String umzuwandeln, haben Sie die beiden folgenden Lösungen:

  • mit format()am nächsten sprintf():

    final static String HexChars = "0123456789abcdef";
    
    public static String getHexQuad(long v) {
        String ret;
        if(v > 0xffff) ret = getHexQuad(v >> 16); else ret = "";
        ret += String.format("%c%c%c%c",
            HexChars.charAt((int) ((v >> 12) & 0x0f)),
            HexChars.charAt((int) ((v >>  8) & 0x0f)),
            HexChars.charAt((int) ((v >>  4) & 0x0f)),
            HexChars.charAt((int) ( v        & 0x0f)));
        return ret;
    }
    
  • mit replace(char oldchar , char newchar)etwas schneller, aber ziemlich begrenzt:

        ...
        ret += "ABCD".
            replace('A', HexChars.charAt((int) ((v >> 12) & 0x0f))).
            replace('B', HexChars.charAt((int) ((v >>  8) & 0x0f))).
            replace('C', HexChars.charAt((int) ((v >>  4) & 0x0f))).
            replace('D', HexChars.charAt((int) ( v        & 0x0f)));
        ...
    
  • Es gibt eine dritte Lösung, die darin besteht, einfach das Zeichen hinzuzufügen ret eins nach dem anderen (char sind Zahlen, die einander ergänzen!) wie in:

    ...
    ret += HexChars.charAt((int) ((v >> 12) & 0x0f)));
    ret += HexChars.charAt((int) ((v >>  8) & 0x0f)));
    ...
    

… aber das wäre Ja wirklich hässlich.

Benutzer-Avatar
armagedescu

Sie können ein printf mit einem PrintStream für alles ausführen, was ein OutputStream ist. Irgendwie so, in einen String-Stream drucken:

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());

Dies gibt folgenden Text aus Es gibt ein Hallo von 3 Freunden
Der String-Stream kann wie dieser ByteArrayOutputStream erstellt werden:

ByteArrayOutputStream baos = new ByteArrayOutputStream();

Sie können viele Formate ansammeln:

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s ", "hello", 3, "friends");
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());

Dies gibt aus Es gibt ein Hallo von 3 Freunden. Es gibt 2 Küsse von einem Mädchen

Rufen Sie reset auf ByteArrayOutputStream auf, um einen sauberen neuen String zu generieren

ps.printf("there is a %s from %d %s", "flip", 5, "haters");
baos.reset(); //need reset to write new string
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());

Die Ausgabe wird sein Es gibt 2 Küsse von einem Mädchen

1018320cookie-checkSprintf-Äquivalent in Java

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy