Logger slf4j ข้อดีของการจัดรูปแบบด้วย {} แทนการต่อสายอักขระ


106

มีข้อดีของการใช้{}แทนการต่อสตริงหรือไม่?

ตัวอย่างจาก slf4j

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

แทน

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

ฉันคิดว่ามันเกี่ยวกับการเพิ่มประสิทธิภาพความเร็วเนื่องจากการประเมินพารามิเตอร์ (และการต่อสตริง) สามารถหลีกเลี่ยงได้ในรันไทม์ขึ้นอยู่กับไฟล์กำหนดค่า แต่เป็นไปได้เพียงสองพารามิเตอร์บางครั้งก็ไม่มีทางเลือกอื่นนอกจากการต่อสตริง ต้องการความเห็นเกี่ยวกับปัญหานี้

คำตอบ:


77

มันเป็นเกี่ยวกับประสิทธิภาพ concatenation สตริง อาจมีนัยสำคัญหากคุณมีข้อความบันทึกที่หนาแน่น

(ก่อนหน้า SLF4J 1.7) แต่เป็นไปได้เพียงสองพารามิเตอร์เท่านั้น

เนื่องจากข้อความบันทึกส่วนใหญ่มีพารามิเตอร์ 2 ตัวหรือน้อยกว่าดังนั้น SLF4J API ถึงเวอร์ชัน 1.6 จึงครอบคลุมกรณีการใช้งานส่วนใหญ่ (เท่านั้น) นักออกแบบ API ได้จัดเตรียมเมธอดที่มากเกินไปพร้อมพารามิเตอร์ varargs ตั้งแต่ API เวอร์ชัน 1.7

สำหรับกรณีที่คุณต้องการมากกว่า 2 และคุณติดอยู่กับ pre-1.7 SLF4J จากนั้นใช้การต่อสายอักขระหรือnew Object[] { param1, param2, param3, ... }. ควรมีไม่กี่คนที่ประสิทธิภาพไม่สำคัญเท่า


2
ควรหลีกเลี่ยงการต่อสายอักขระที่ไม่ได้ใช้ (เช่นคำสั่งการดีบัก) ใช้การตรวจสอบระดับบันทึก (ละเอียดเกินไป แต่มีประสิทธิภาพ) หรือพารามิเตอร์อาร์เรย์อ็อบเจ็กต์ (บางกว่า แต่อาจมีค่าใช้จ่ายเล็กน้อย) (ฉันชอบอย่างหลังมากกว่าทุกสิ่งจะเท่ากัน) เป็นการยากที่จะบอกว่าการต่อสตริงจะไม่สำคัญ / ไม่ส่งผลกระทบต่อประสิทธิภาพ ในทางทฤษฎีการสร้างอาร์เรย์อ็อบเจ็กต์อาจอยู่ในแนวอินไลน์และปรับให้เหมาะสมที่สุดและ "จริงๆ" ไม่ได้สร้างความแตกต่าง (เทียบกับความคิดปรารถนา) (ไม่ใช่การเพิ่มประสิทธิภาพก่อนเวลาอันควรเป็นเพียงเรื่องของการทำสิ่งที่ถูกต้อง / ดีกว่าในครั้งแรก)
ไมเคิล

เหตุใดจึงไม่ทำการแก้ไขที่โอเวอร์โหลดสำหรับ System.out.println () ให้ทำตามคล้ายกับคนตัดไม้ของ slf4j เพื่อหลีกเลี่ยงการต่อสายอักขระ?
a3.14_Infinity

45

เวอร์ชันสั้น: ใช่เร็วกว่าด้วยรหัสน้อย!

การต่อสายอักขระทำงานได้มากโดยไม่ทราบว่าจำเป็นหรือไม่ (การทดสอบ "เปิดใช้การดีบักแบบดั้งเดิม" ที่ทราบจาก log4j) และควรหลีกเลี่ยงหากเป็นไปได้เนื่องจาก {} อนุญาตให้หน่วงเวลาการเรียก toString () และการสร้างสตริง หลังจากได้รับการตัดสินแล้วว่าเหตุการณ์นั้นจำเป็นต้องจับภาพหรือไม่ ด้วยการจัดรูปแบบคนตัดไม้เป็นสตริงเดียวรหัสจะสะอาดขึ้นในความคิดของฉัน

คุณสามารถระบุอาร์กิวเมนต์จำนวนเท่าใดก็ได้ โปรดทราบว่าหากคุณใช้ sljf4j เวอร์ชันเก่าและคุณมีอาร์กิวเมนต์มากกว่าสองอาร์กิวเมนต์{}คุณต้องใช้new Object[]{a,b,c,d}ไวยากรณ์เพื่อส่งผ่านอาร์เรย์แทน ดูเช่นhttp://slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String, java.lang.Object [])

เกี่ยวกับความเร็ว: Ceki โพสต์เกณฑ์มาตรฐานในขณะที่กลับมาในรายการใดรายการหนึ่ง


6
หมายเหตุ: javadoc ล่าสุดแสดงไวยากรณ์ var-arg ที่ใหม่กว่า, debug(String format, Object... arguments). ดูslf4j.org/faq.html#logging_performance
michael

โหวตเพิ่มขึ้นเนื่องจากมีการกล่าวถึงการประเมินผล. toString () นอกเหนือจากประสิทธิภาพการเรียงต่อกัน นี่คือสิ่งที่เกิดขึ้นภายในคนตัดไม้และคนตัดไม้สามารถตัดสินใจได้ว่าจำเป็นต้องเรียกใช้วิธีนั้นหรือไม่ ไม่ได้หากไม่ตรงตามแถบระดับการบันทึก
Chetan Narsude

6

เนื่องจาก String ไม่เปลี่ยนรูปใน Java ดังนั้นจึงต้องคัดลอก String ด้านซ้ายและขวาลงใน String ใหม่สำหรับการเชื่อมต่อทุกคู่ ดังนั้นไปหาตัวยึดจะดีกว่า


2
สิ่งนี้ถูกต้องหากมีคู่เดียว แต่โดยทั่วไปไม่ถูกต้องเนื่องจากคอมไพเลอร์เปลี่ยนการเชื่อมต่อกันเป็นการเรียกตัวสร้างสตริงส่งผลให้โค้ดเร็วขึ้นมากซึ่งไม่ได้ทำการจัดสรรมากนัก
cdeszaq

3

String.format()ทางเลือกหนึ่งคือ เรากำลังใช้มันในjcabi-log (เครื่องห่อยูทิลิตี้แบบคงที่รอบ ๆ slf4j)

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

สามารถบำรุงรักษาและขยายได้มากขึ้น นอกจากนี้ยังง่ายต่อการแปล


3
ฉันไม่คิดว่ามันจะบำรุงรักษาได้มากกว่านี้ หากประเภทของvalueการเปลี่ยนแปลงคุณต้องย้อนกลับและเปลี่ยนคำสั่งการบันทึกด้วย สิ่งที่ IDE จะไม่ช่วยคุณ คนตัดไม้ควรช่วยในการแก้ไขข้อบกพร่องและอย่าเข้ามาขัดขวาง :-)
Chetan Narsude

3
@ChetanNarsude IntelliJ 2016 อย่างน้อยก็บอกฉันเมื่อสตริงรูปแบบไม่พอดีกับอาร์กิวเมนต์การจัดรูปแบบ ตัวอย่างเช่นผู้ผลิตเตือนString.format("%d", "Test") IntelliJ Argument type 'String' does not match the type of the format specifier '%d'.แม้ว่าฉันไม่แน่ใจว่าจะยังสามารถตอบสนองที่ชาญฉลาดนี้ได้เมื่อทำงานกับโซลูชันข้างต้น
ขยี้

ความเร็วของสิ่งนี้คืออะไร?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersenมันค่อนข้างดั้งเดิมภายใน แต่แน่นอนว่ามันช้ากว่าคนตัดไม้แบบคงที่
yegor256

ห่อ slf4j? นั่นไม่ทำให้จุดประสงค์ของการใช้ slf4j หรือไม่ นอกจากนี้ฉันยังเคยเห็นหลาย ๆ คนใช้ String.format ในทางที่ผิดเพื่อให้สตริงได้รับการจัดรูปแบบก่อนที่ระดับบันทึกจะได้รับการประเมินเช่น: logger.info (String.format ("hello% s", ชื่อผู้ใช้))
Juan Bustamante

2

ฉันคิดว่าจากมุมมองของผู้เขียนเหตุผลหลักคือการลดค่าใช้จ่ายสำหรับการต่อสตริงฉันเพิ่งอ่านเอกสารของคนตัดไม้คุณจะพบคำต่อไปนี้:

/**
* <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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.