Printf został dodany do Javy w wersji 1.5, ale nie mogę znaleźć sposobu, aby wysłać dane wyjściowe do łańcucha zamiast do pliku (co robi sprintf w C). Czy ktoś wie jak to zrobić?
Printf został dodany do Javy w wersji 1.5, ale nie mogę znaleźć sposobu, aby wysłać dane wyjściowe do łańcucha zamiast do pliku (co robi sprintf w C). Czy ktoś wie jak to zrobić?
Odpowiedzi:
// Store the formatted string in 'result'
String result = String.format("%4d", i * j);
// Write the result to standard output
System.out.println( result );
Ciągi są niezmiennymi typami. Nie możesz ich modyfikować, zwracaj tylko nowe wystąpienia ciągów.
Z tego powodu formatowanie za pomocą metody instancji nie ma większego sensu, ponieważ należałoby ją wywołać w następujący sposób:
String formatted = "%s: %s".format(key, value);
Oryginalni autorzy Java (i autorzy .NET) zdecydowali, że metoda statyczna ma większy sens w tej sytuacji, ponieważ nie modyfikujesz obiektu docelowego, ale zamiast tego wywołujesz metodę formatowania i przekazujesz ciąg wejściowy.
Oto przykład, dlaczego format()
miałby być głupi jako metoda instancji. W .NET (i prawdopodobnie w Javie) Replace()
jest metodą instancji.
Możesz to zrobić:
"I Like Wine".Replace("Wine","Beer");
Jednak nic się nie dzieje, ponieważ ciągi są niezmienne. Replace()
próbuje zwrócić nowy ciąg, ale jest on przypisany do niczego.
Powoduje to wiele typowych błędów debiutantów, takich jak:
inputText.Replace(" ", "%20");
Ponownie nic się nie dzieje, zamiast tego musisz zrobić:
inputText = inputText.Replace(" ","%20");
Jeśli zrozumiesz, że ciągi są niezmienne, ma to doskonały sens. Jeśli nie, to jesteś po prostu zdezorientowany. Właściwym miejscem Replace()
byłoby, gdzie format()
jest, jako statyczna metoda String
:
inputText = String.Replace(inputText, " ", "%20");
Teraz nie ma wątpliwości, co się dzieje.
Prawdziwe pytanie brzmi: dlaczego autorzy tych ram zdecydowali, że jedna powinna być metodą instancji, a druga statyczna? Moim zdaniem oba są bardziej elegancko wyrażone jako metody statyczne.
Niezależnie od twojej opinii, prawda jest taka, że masz mniejszą skłonność do popełniania błędów przy użyciu wersji statycznej, a kod jest łatwiejszy do zrozumienia (brak ukrytych błędów).
Oczywiście istnieją pewne metody, które są doskonałe jako metody instancji, weź String.Length ()
int length = "123".Length();
W tej sytuacji jest oczywiste, że nie próbujemy modyfikować „123”, po prostu go sprawdzamy i zwracamy jego długość. Jest to idealny kandydat na metodę instancji.
Moje proste zasady dotyczące metod instancji na obiektach niezmiennych:
Oba rozwiązania symulują printf, ale w inny sposób. Na przykład, aby przekonwertować wartość na ciąg szesnastkowy, masz 2 następujące rozwiązania:
z format()
najbliżej 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;
}
z replace(char oldchar , char newchar)
, nieco szybszym, ale dość ograniczonym:
...
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)));
...
Istnieje trzecie rozwiązanie polegające na dodaniu char do ret
jednego po drugim (char to liczby, które się dodają !), Na przykład:
...
ret += HexChars.charAt((int) ((v >> 12) & 0x0f)));
ret += HexChars.charAt((int) ((v >> 8) & 0x0f)));
...
... ale to byłoby naprawdę brzydkie.
Możesz zrobić printf do wszystkiego, co jest OutputStream z PrintStream. Jakoś tak, drukując do strumienia ciągów:
PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());
baos.reset(); //need reset to write new string
ps.printf("there is a %s from %d %s", "flip", 5, "haters");
System.out.println(baos.toString());
baos.reset();
Strumień ciągu można utworzyć w następujący sposób ByteArrayOutputStream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();