Setara dengan Sprintf di Jawa


284

Printf ditambahkan ke Java dengan rilis 1.5 tapi sepertinya saya tidak bisa menemukan cara mengirim output ke string daripada file (yang dilakukan sprintf di C). Adakah yang tahu bagaimana melakukan ini?

Jawaban:


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

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

Lihat format dan sintaksnya


28

String adalah tipe yang tidak berubah. Anda tidak dapat memodifikasinya, hanya mengembalikan instance string baru.

Karena itu, memformat dengan metode instan tidak masuk akal, karena harus dipanggil seperti:

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

Penulis Java asli (dan .NET penulis) memutuskan bahwa metode statis lebih masuk akal dalam situasi ini, karena Anda tidak memodifikasi target, tetapi memanggil metode format dan mengirimkan string input.

Berikut adalah contoh mengapa format()menjadi bodoh sebagai metode contoh. Dalam. NET (dan mungkin di Jawa), Replace()adalah metode instance.

Kamu bisa melakukan ini:

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

Namun, tidak ada yang terjadi, karena string tidak dapat diubah. Replace()mencoba mengembalikan string baru, tetapi tidak diberikan apa pun.

Ini menyebabkan banyak kesalahan rookie umum seperti:

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

Sekali lagi, tidak ada yang terjadi, yang harus Anda lakukan:

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

Sekarang, jika Anda mengerti bahwa string tidak dapat diubah, itu masuk akal. Jika tidak, berarti Anda bingung. Tempat yang tepat untuk Replace()berada format()adalah, sebagai metode statis String:

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

Sekarang tidak ada pertanyaan tentang apa yang terjadi.

Pertanyaan sebenarnya adalah, mengapa para penulis kerangka kerja ini memutuskan bahwa yang satu harus menjadi metode instan, dan yang lainnya statis? Menurut pendapat saya, keduanya lebih elegan diungkapkan sebagai metode statis.

Terlepas dari pendapat Anda, kebenarannya adalah bahwa Anda kurang rentan membuat kesalahan dengan menggunakan versi statis, dan kodenya lebih mudah dipahami (No Hidden Gotchas).

Tentu saja ada beberapa metode yang sempurna sebagai metode instance, ambil String.Length ()

int length = "123".Length();

Dalam situasi ini, sudah jelas kami tidak mencoba untuk memodifikasi "123", kami hanya memeriksanya, dan mengembalikan panjangnya. Ini adalah kandidat yang sempurna untuk metode instan.

Aturan sederhana saya untuk Metode Instance pada Objek yang Tidak Berubah:

  • Jika Anda perlu mengembalikan instance baru dari jenis yang sama, gunakan metode statis.
  • Jika tidak, gunakan metode instan.

4
Saya melihat bahwa Anda mendapatkan ide yang saya sarankan agar format string diubah. Saya tidak pernah mempertimbangkan kemungkinan bahwa seseorang mungkin berharap String akan berubah, karena ketidakmampuan mereka sangat mendasar.
erickson

4
Melihat format string biasanya lebih seperti "Harga adalah% 4d", dan bukan "% 4d", saya masih melihat banyak potensi kebingungan. Apa yang Anda miliki terhadap metode statis? :)
FlySwat

44
Jawaban ini sepertinya tidak ada hubungannya dengan pertanyaan.
Steve McLeod

2
Jawabannya bahkan bukan Java, tampaknya lebih relevan untuk .NET
Photodeus

3
-1. Diturunkan karena itu tangensial. Dan belum tentu gaya terbaik untuk kekal. Gaya ini lebih verbose daripada pemanggilan metode sederhana, khususnya untuk operasi berantai. Dan itu melepaskan polimorfisme run-time karena itu memanggil metode statis, yang penting. YMMV.
Andrew Janke

3

Kedua solusi berfungsi untuk mensimulasikan printf, tetapi dengan cara yang berbeda. Misalnya, untuk mengonversi nilai ke string hex, Anda memiliki 2 solusi berikut:

  • dengan format(), paling dekat dengan 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;
    }
  • dengan replace(char oldchar , char newchar), agak lebih cepat tetapi sangat terbatas:

        ...
        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)));
        ...
  • Ada solusi ketiga yang terdiri dari hanya menambahkan char ke retsatu per satu (char adalah angka yang saling menambah !) Seperti di:

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

... tapi itu akan sangat jelek.


Semua ide bagus, tetapi mengubah kode Anda menjadi kode hanya-tulis yang mustahil dipahami oleh rekan kerja Anda.
Ben

0

Anda dapat melakukan printf untuk apa pun yang merupakan OutputStream dengan PrintStream. Entah seperti ini, mencetak ke aliran string:

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

Aliran string dapat dibuat seperti ini ByteArrayOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.