Keuntungan logger slf4j dari pemformatan dengan {} daripada penggabungan string

100

Apakah ada keuntungan menggunakan {}daripada penggabungan string?

Contoh dari slf4j

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

dari pada

logger.debug("Temperature set to"+ t + ". Old temperature was " + oldT);

Saya pikir ini tentang pengoptimalan kecepatan karena evaluasi parameter (dan penggabungan string) dapat dihindari dalam runtime tergantung pada file konfigurasi. Tetapi hanya dua parameter yang memungkinkan, maka terkadang tidak ada pilihan lain selain penggabungan string. Membutuhkan pandangan tentang masalah ini.

Hernán Eche
sumber

Jawaban:

74

Ini adalah tentang kinerja string concatenation. Ini berpotensi signifikan jika Anda memiliki laporan logging yang padat.

(Sebelum SLF4J 1.7) Tetapi hanya dua parameter yang memungkinkan

Karena sebagian besar pernyataan logging memiliki 2 parameter atau lebih sedikit, maka SLF4J API hingga versi 1.6 mencakup (hanya) sebagian besar kasus penggunaan. Desainer API telah menyediakan metode kelebihan beban dengan parameter varargs sejak API versi 1.7.

Untuk kasus-kasus di mana Anda membutuhkan lebih dari 2 dan Anda terjebak dengan pra-1.7 SLF4J, maka gunakan saja penggabungan string atau new Object[] { param1, param2, param3, ... }. Jumlahnya harus sedikit sehingga kinerjanya tidak terlalu penting.

skaffman
sumber
2
Rangkaian string yang tidak digunakan (misalnya pernyataan debugging) harus dihindari. Gunakan baik pemeriksaan tingkat log (terlalu bertele-tele tapi efisien) atau parameter larik objek (lebih ramping, tapi mungkin overhead kecil). (Saya lebih suka yang terakhir, semua hal dianggap sama.) Sulit untuk mengatakan bahwa rangkaian string tidak akan penting / tidak akan memengaruhi kinerja. Penciptaan larik objek secara teori dapat menjadi inline dan dioptimalkan dan "benar-benar" tidak membuat perbedaan (vs. angan-angan). (Ini bukan pengoptimalan prematur, ini hanya masalah melakukan sesuatu dengan benar / lebih baik untuk pertama kalinya.)
michael
mengapa modifikasi yang kelebihan beban tidak dilakukan untuk System.out.println () mengikuti seperti logger slf4j, sehingga menghindari penggabungan string?
a3.14_Infinity
45

Versi singkat: Ya, lebih cepat, dengan lebih sedikit kode!

Penggabungan string melakukan banyak pekerjaan tanpa mengetahui apakah itu diperlukan atau tidak (pengujian tradisional "sedang debugging diaktifkan" yang dikenal dari log4j), dan harus dihindari jika memungkinkan, karena {} memungkinkan penundaan panggilan toString () dan konstruksi string ke setelah diputuskan apakah acara tersebut perlu direkam atau tidak. Dengan memiliki format logger satu string kode menjadi lebih bersih menurut saya.

Anda dapat memberikan sejumlah argumen. Perhatikan bahwa jika Anda menggunakan versi lama sljf4j dan Anda memiliki lebih dari dua argumen {}, Anda harus menggunakan new Object[]{a,b,c,d}sintaks untuk meneruskan larik. Lihat misalnya http://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object []) .

Mengenai kecepatan: Ceki sempat membukukan patokan di salah satu daftar.

Thorbjørn Ravn Andersen
sumber
6
catatan: javadoc terbaru menampilkan sintaks var-arg yang lebih baru debug(String format, Object... arguments),. Lihat slf4j.org/faq.html#logging_performance
michael
Diberikan suara positif karena menyebutkan evaluasi .toString () selain kinerja rangkaian. Ini adalah sesuatu yang terjadi di dalam logger dan logger dapat memutuskan apakah perlu untuk memanggil metode itu. Ini tidak terjadi jika bilah level logging tidak terpenuhi.
Chetan Narsude
6

Karena, String tidak dapat diubah di Java, jadi String kiri dan kanan harus disalin ke String baru untuk setiap pasangan penggabungan. Jadi, lebih baik pilih placeholder.

Rabin Pantha
sumber
2
Ini benar jika ada satu pasangan, tetapi umumnya salah, karena compiler mengubah penggabungan menjadi panggilan pembuat string, menghasilkan kode yang jauh lebih cepat yang tidak melakukan banyak alokasi.
cdeszaq
3

Alternatif lainnya adalah String.format(). Kami menggunakannya di jcabi-log (pembungkus utilitas statis di sekitar slf4j).

Logger.debug(this, "some variable = %s", value);

Ini jauh lebih mudah dirawat dan diperpanjang. Selain itu, mudah untuk diterjemahkan.

yegor256
sumber
3
Saya tidak berpikir itu lebih mudah dirawat. jika jenisnya valueberubah, Anda harus kembali dan mengubah pernyataan logging juga. Sesuatu yang IDE tidak akan membantu Anda. Logger harus membantu dengan debugging dan tidak menghalangi itu. :-)
Chetan Narsude
3
@ChetanNarsude IntelliJ 2016 setidaknya memberi tahu saya ketika string format tidak sesuai dengan argumen pemformatan. Misalnya: String.format("%d", "Test")menghasilkan peringatan IntelliJ Argument type 'String' does not match the type of the format specifier '%d'.. Meskipun, saya tidak yakin ini masih dapat memberikan respons cerdas ini saat bekerja dengan solusi di atas.
hancurkan
berapa kecepatan ini?
Thorbjørn Ravn Andersen
@ ThorbjørnRavnAndersen itu cukup primitif di dalam, tapi tentu saja itu lebih lambat dari logger statis
yegor256
Membungkus slf4j? bukankah itu menggagalkan tujuan menggunakan slf4j? Juga, saya telah melihat banyak orang menyalahgunakan String.format sedemikian rupa sehingga string diformat sebelum tingkat log dievaluasi, seperti: logger.info (String.format ("hello% s", username)).
Juan Bustamante
2

Saya pikir dari sudut pandang penulis, alasan utamanya adalah untuk mengurangi overhead untuk penggabungan string. Saya baru saja membaca dokumentasi logger, Anda dapat menemukan kata-kata berikut:

/**
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an <code>Object[]</code> before 
  invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*/
*
 * @param format    the format string
 * @param arguments a list of 3 or more arguments
 */
public void debug(String format, Object... arguments);
Tianhao Wang
sumber