Java'da Sprintf eşdeğeri


284

Printf 1.5 sürümüyle Java'ya eklendi, ancak çıktıyı bir dosya yerine bir dizeye nasıl göndereceğimi göremiyorum (sprintf'in yaptığı şey budur). Bunu nasıl yapacağını bilen var mı?

Yanıtlar:


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

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

Biçime ve sözdizimine bakın


28

Dizeler değişmez türlerdir. Bunları değiştiremezsiniz, yalnızca yeni dize örnekleri döndürürsünüz.

Bu nedenle, bir örnek yöntemiyle biçimlendirme, şöyle adlandırılması gerektiği için çok az mantıklıdır:

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

Orijinal Java yazarları (ve .NET yazarları), hedefi değiştirmediğinizden, bunun yerine bir biçim yöntemini çağırdığınızda ve bir giriş dizesi geçirdiğinden, bu durumda statik bir yöntemin daha anlamlı olduğuna karar verdiler.

Örnek format()bir yöntem olarak neden aptal olabileceğinin bir örneği. .NET'te (ve muhtemelen Java'da) Replace()bir örnek yöntemidir.

Bunu yapabilirsiniz:

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

Ancak, hiçbir şey olmaz, çünkü dizeler değişmezdir. Replace()yeni bir dize döndürmeye çalışır, ancak hiçbir şeye atanmaz.

Bu, aşağıdakiler gibi birçok yaygın çaylak hatasına neden olur:

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

Yine, hiçbir şey olmuyor, bunun yerine yapmanız gerekenler:

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

Şimdi, dizelerin değişmez olduğunu anlarsanız, bu çok mantıklıdır. Eğer yapmazsan, o zaman kafan karışır. İçin uygun bir yer Replace()nerede olacağını format()ise statik yöntemi olarak, String:

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

Şimdi neler olduğu hakkında bir soru yok.

Asıl soru şu ki, bu çerçevelerin yazarları neden birinin örnek yöntem ve diğerinin statik olması gerektiğine karar verdiler? Bence, her ikisi de statik yöntemler olarak daha zarif bir şekilde ifade ediliyor.

Fikriniz ne olursa olsun, gerçek şu ki, statik sürümü kullanarak hata yapmaya daha az eğilimlisiniz ve kodun anlaşılması daha kolay (Gizli Gotchas yok).

Tabii ki örnek yöntemler olarak mükemmel olan bazı yöntemler vardır, String.Length ()

int length = "123".Length();

Bu durumda, "123" ü değiştirmeye çalışmadığımız açıktır, sadece inceliyoruz ve uzunluğunu döndürüyoruz. Bu, bir örnek yöntemi için mükemmel bir adaydır.

Değişken Nesneler Üzerindeki Örnek Yöntemleri için basit kurallarım:

  • Aynı türde yeni bir örnek döndürmeniz gerekiyorsa, statik bir yöntem kullanın.
  • Aksi takdirde, bir örnek yöntemi kullanın.

4
Biçim dizesinin değiştirilmesini önerdiğim fikri bir şekilde bulduğunuzu görüyorum. Birisinin bir String'in değişmesini bekleyebileceği ihtimalini hiç düşünmedim, çünkü değişmezlikleri çok temel.
erickson

4
Biçim dizesi genellikle "Fiyat% 4d" ve "% 4d" gibi görünmüyor, hala karışıklık için çok fazla potansiyel görüyorum. Statik yöntemlere karşı neyiniz var? :)
FlySwat

44
Bu cevabın soru ile ilgisi yok gibi görünüyor.
Steve McLeod

2
Cevap Java bile değil, .NET ile daha ilgili gibi görünüyor
Photodeus

3
-1. B / c indirildi teğet. Ve mutlaka değişmezler için en iyi stil değil. Bu tarz, özellikle zincirleme işlemler için basit yöntem çağrılarından daha ayrıntılıdır. Ve çalışma zamanı polimorfizminden vazgeçiyor çünkü önemli olan statik yöntemleri çağırıyor. YMMV.
Andrew Janke

3

Her iki çözüm de printf'i simüle etmek için çalışır, ancak farklı bir şekilde. Örneğin, bir değeri onaltılı bir dizeye dönüştürmek için aşağıdaki 2 çözüme sahip olursunuz:

  • ile format(), en yakın 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;
    }
  • ile replace(char oldchar , char newchar)biraz daha hızlı ama oldukça sınırlı:

        ...
        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)));
        ...
  • Aşağıdaki gibi sadece karakterleri rettek tek eklemekten oluşan üçüncü bir çözüm var (karakter birbirine eklenen sayılardır !):

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

... ama bu gerçekten çirkin olurdu .


Tüm harika fikirler, ancak kodunuzu iş arkadaşınız için anlaşılması imkansız salt okunur koda dönüştürür.
Ben

0

PrintStream ile bir OutputStream olan herhangi bir şeye printf yapabilirsiniz. Her nasılsa, bir dize akışına yazdırmak:

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

Dize akışı şu ByteArrayOutputStream gibi oluşturulabilir:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.