2008-09-05 15 views
245

Printf wurde zu Java mit der Version 1.5 hinzugefügt, aber ich kann nicht finden, wie man die Ausgabe an eine Zeichenkette anstatt an eine Datei sendet (was sprintf in C tut). Weiß jemand, wie man das macht?Sprintf-Entsprechung in Java

Antwort

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

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

Siehe format und seine syntax

22

@erickson.

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

Dieses Grund, „foo“ .format() macht wenig Sinn, da es wie

string newString = "foo".format(); 

Die ursprünglichen Java-Autoren (und .NET-Autoren) genannt werden müßte, entschieden, dass eine statische Methode In dieser Situation ist es sinnvoller, wenn Sie nicht "foo" ändern, sondern stattdessen eine Formatmethode aufrufen und eine Eingabezeichenfolge übergeben.

EDIT: Heh, diese Seite kann manchmal so amüsant sein. Ich wurde abgelehnt, weil ich erwähnt habe, dass Strings unveränderliche Typen sind.

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

Sie können dies tun:

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

jedoch nichts passiert, weil Strings unveränderlich sind. Ersetzen versucht, eine neue Zeichenfolge zurückzugeben, aber es wird nichts zugewiesen.

Dies bewirkt, dass viele gemeinsame Anfängerfehler wie:

// Contrived Example 
inputText.Replace(" ","%20"); 

Wieder geschieht nichts, stattdessen müssen Sie tun:

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

Nun, wenn Sie verstehen, dass Strings unveränderlich sind, dass Marken Perfekter Sinn. Wenn Sie das nicht tun, dann sind Sie nur verwirrt. Der richtige Ort für ersetzen, wäre in dem Format ist, als statische Methode von String:

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

Jetzt gibt es keine Frage, was los ist.

Die eigentliche Frage ist, warum haben die Autoren dieser Frameworks entschieden, dass man eine Instanz-Methode sein sollte, und die andere statische? Meiner Meinung nach werden beide eleganter als statische Methoden ausgedrückt, aber Erickson scheint zu denken, dass beide als Instanzmethoden gehören.

Unabhängig von Ihrer Meinung, die Wahrheit ist, dass Sie weniger anfällig sind, einen Fehler mit der statischen Version zu machen, und der Code ist leichter zu verstehen (No Hidden Gotchas).

Natürlich gibt es einige Methoden, die als Instanzmethoden perfekt sind, nehmen String.length()

int length = "123".Length(); 

In dieser Situation seine offensichtlich, dass wir nicht ändern „123“ versucht, die Kontrolle wir es einfach und seine Länge zurückgibt ... Dies ist ein perfekter Kandidat für eine Instanzmethode.

Meine einfache Regeln für die Instanzmethoden auf unveränderliche Objekte:

  • Wenn Sie eine neue Instanz des gleichen Typs zurückkommen müssen, verwenden Sie eine statische Methode.
  • Andernfalls verwenden Sie eine Instanzmethode.
+3

Ich sehe, dass Sie irgendwie die Idee hatten, ich schlug vor, dass die Formatzeichenfolge geändert werden sollte. Ich habe nie über die Möglichkeit nachgedacht, dass jemand erwarten könnte, dass sich eine Zeichenfolge ändert, da ihre Unveränderbarkeit so grundlegend ist. – erickson

+4

Da die Formatzeichenfolge eher wie "Der Preis ist% 4d" und nicht "% 4d" aussieht, sehe ich immer noch viel Verwirrungspotenzial. Was hast du gegen statische Methoden? :) – FlySwat

+38

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

2

Beide Lösungen simulieren printf, aber auf andere Weise. zum Beispiel einen Wert in eine Hex-String zu konvertieren, müssen Sie die 2 folgenden Lösungen:

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

    final static String HexChars = "abcdef"; 
    
    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 bestehend aus nur ad ding der char ret eins nach dem anderen (char sind Zahlen, die zueinander hinzufügen !) wie in:

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

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

+0

Alle großen Ideen, aber macht Ihren Code in Schreib-Code für Ihren Mitarbeiter unmöglich zu verstehen. – Ben