ใน Java ทำไมมันเป็นวิธีที่ดีที่สุดที่จะประกาศคนตัดไม้static final
?
private static final Logger S_LOGGER
ใน Java ทำไมมันเป็นวิธีที่ดีที่สุดที่จะประกาศคนตัดไม้static final
?
private static final Logger S_LOGGER
คำตอบ:
private
- เพื่อไม่ให้ชั้นเรียนอื่นสามารถจี้คนตัดไม้ของคุณได้static
- ดังนั้นจึงมีอินสแตนซ์คนตัดไม้เพียงหนึ่งรายการต่อคลาสและหลีกเลี่ยงความพยายามที่จะทำให้คนตัดไม้เป็นอนุกรมfinal
- ไม่จำเป็นต้องเปลี่ยนคนตัดไม้ตลอดอายุการใช้งานของคลาสนอกจากนี้ฉันชอบตั้งชื่อlog
ให้เรียบง่ายที่สุด แต่สื่อความหมายได้ดี
แก้ไข: อย่างไรก็ตามมีข้อยกเว้นที่น่าสนใจสำหรับกฎเหล่านี้:
protected final Logger log = LoggerFactory.getLogger(getClass());
ตรงข้ามกับ:
private static final Logger log = LoggerFactory.getLogger(Foo.class);
วิธีเดิมช่วยให้คุณใช้ชื่อคนตัดไม้เดียวกัน (ชื่อของคลาสจริง) ในทุกคลาสตลอดลำดับชั้นการสืบทอด ดังนั้นหากBar
ขยายFoo
ทั้งคู่จะเข้าสู่ระบบBar
คนตัดไม้ บางคนพบว่าใช้งานง่ายกว่า
log
LOG
แค่เรื่องของ dev. ข้อตกลงของทีม
ตรวจสอบการโพสต์บล็อกนี้: กำจัดของ Java คงตัดไม้ นี่คือวิธีที่คุณใช้ slf4j กับjcabi-log :
import com.jcabi.log.Logger;
class Foo {
void save(File f) {
Logger.info(this, "file %s saved successfully", f);
}
}
และอย่าใช้เสียงคงที่อีกต่อไป
static
หมายความว่าคุณจะสร้าง Logger ได้เพียงหนึ่งคนต่อคลาสเท่านั้นไม่ใช่หนึ่งคนตัดไม้ต่ออินสแตนซ์ของคลาสของคุณ โดยทั่วไปนี่คือสิ่งที่คุณต้องการเนื่องจากคนตัดไม้มักจะแตกต่างกันไปตามชั้นเรียนเท่านั้น
final
หมายความว่าคุณจะไม่เปลี่ยนค่าของlogger
ตัวแปร ซึ่งเป็นความจริงเนื่องจากคุณมักจะโยนข้อความบันทึกทั้งหมด (จากคลาสเดียว) ไปยังคนตัดไม้คนเดียวกัน แม้ในบางครั้งที่เกิดขึ้นไม่บ่อยนักที่ชั้นเรียนอาจต้องการส่งข้อความบางอย่างไปยังคนตัดไม้คนอื่นมันจะชัดเจนกว่ามากที่จะสร้างตัวแปรคนตัดไม้อื่น (เช่นwidgetDetailLogger
) แทนที่จะเปลี่ยนค่าของตัวแปรคงที่ทันที
คุณต้องการเปลี่ยนค่าของฟิลด์เมื่อใด
หากคุณจะไม่เปลี่ยนค่าการทำให้ฟิลด์สุดท้ายทำให้เห็นได้ชัดว่าคุณจะไม่มีวันเปลี่ยนค่า
โดยปกติคุณเริ่มต้นเครื่องบันทึกเพื่อบันทึกโดยใช้ชื่อคลาส - ซึ่งหมายความว่าหากพวกเขาไม่คงที่คุณจะจบลงด้วยการที่แต่ละอินสแตนซ์ของคลาสมีอินสแตนซ์ของมัน (หน่วยความจำสูง) แต่คนตัดไม้เหล่านี้ทั้งหมดจะ แบ่งปันการกำหนดค่าเดียวกันและทำงานเหมือนกันทุกประการ นั่นคือเหตุผลเบื้องหลังstatic
บิต เนื่องจากแต่ละชื่อLogger
เริ่มต้นด้วยชื่อคลาสเพื่อป้องกันความขัดแย้งกับคลาสย่อยคุณจึงประกาศprivate
ดังนั้นจึงไม่สามารถสืบทอดได้ final
มาจากจุดที่คุณตามปกติไม่ได้เปลี่ยนLogger
ในระหว่างการดำเนินการ - ดังนั้นเมื่อเริ่มต้นที่คุณไม่เคย "กำหนดค่าใหม่" มัน - ในกรณีที่มันทำให้ความรู้สึกที่จะทำให้มันเป็นครั้งสุดท้ายเพื่อให้แน่ใจว่าไม่มีใครสามารถเปลี่ยนได้ (โดย ผิดพลาดหรืออย่างอื่น) แน่นอนถ้าคุณจะใช้ไฟล์Logger
ด้วยวิธีอื่นที่คุณอาจไม่จำเป็นต้องใช้static final
- แต่ฉันอยากจะเดาว่า 80% ของแอปจะใช้การบันทึกตามที่อธิบายไว้ข้างต้น
ในการตอบคำถามนั้นคุณควรถามตัวเองว่า "คงที่" และ "สุดท้าย" มีไว้เพื่ออะไร
สำหรับ Logger (ฉันสมมติว่าคุณพูดถึงคลาส Log4J Logger) คุณต้องการประเภทต่อคลาส ซึ่งควรนำไปสู่การที่คุณกำหนดเพียงครั้งเดียวและไม่จำเป็นต้องมีมากกว่าหนึ่งอินสแตนซ์ต่อคลาส และสันนิษฐานว่าไม่มีเหตุผลที่จะเปิดเผยอ็อบเจ็กต์ Logger ของคลาสหนึ่งไปยังอีกคลาสหนึ่งดังนั้นทำไมไม่ทำให้เป็นแบบส่วนตัวและปฏิบัติตามหลักการ OO บางประการ
นอกจากนี้คุณควรทราบด้วยว่าคอมไพเลอร์สามารถใช้ประโยชน์จากสิ่งนั้นได้ ดังนั้นโค้ดของคุณจึงทำงานได้ดีขึ้นเล็กน้อย :)
เนื่องจากโดยปกติแล้วฟังก์ชันนี้เป็นฟังก์ชันที่สามารถใช้ร่วมกันได้ในทุกอินสแตนซ์ของวัตถุของคุณ มันไม่สมเหตุสมผลมากนัก (90% ของเวลา) ที่จะมีคนตัดไม้ที่แตกต่างกันสำหรับสองอินสแตนซ์ของคลาสเดียวกัน
อย่างไรก็ตามคุณยังสามารถเห็นบางครั้งคลาสของคนตัดไม้ที่ประกาศเป็นเสื้อกล้ามหรือแม้แต่เสนอฟังก์ชันคงที่เพื่อบันทึกข้อมูลของคุณ
โค้ดนี้มีช่องโหว่, แต่หลังจาก Java7 เราสามารถใช้Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
แทนสแตติกล็อกเกอร์ได้
This is code is vulnerable
คุณช่วยชี้แจงคุณตอบหน่อยได้ไหม
ในกรณีส่วนใหญ่คุณจะไม่เปลี่ยนข้อมูลอ้างอิงและfinal
ตัวปรับแต่งจะทำเครื่องหมาย คุณไม่จำเป็นต้องแยกกรณีเช่นแต่ละชั้น - static
ดังนั้น และประการแรกคือเพื่อประสิทธิภาพ - สามารถปรับให้เหมาะสม (ขั้นสุดท้าย) และประหยัดหน่วยความจำ (คงที่)
ตามหลักการแล้ว Logger ควรเป็นดังต่อไปนี้จนถึง Java 7 สำหรับการไม่ให้ Sonar และการให้ Compliant Code: private: ไม่สามารถเข้าถึงได้จากภายนอกคลาสหลัก หากชั้นเรียนอื่นต้องการบันทึกบางสิ่งก็ควรสร้างอินสแตนซ์คนตัดไม้ของตัวเอง คงที่: ไม่ต้องขึ้นอยู่กับอินสแตนซ์ของคลาส (อ็อบเจ็กต์) เมื่อทำการบันทึกบางสิ่งแน่นอนสามารถให้ข้อมูลเชิงบริบทในข้อความได้ แต่ควรสร้างตัวบันทึกที่ระดับชั้นเรียนเพื่อป้องกันการสร้างคนตัดไม้พร้อมกับวัตถุแต่ละชิ้นและด้วยเหตุนี้จึงป้องกันรอยเท้าหน่วยความจำสูง ขั้นสุดท้าย: สร้างครั้งเดียวและครั้งเดียวต่อชั้นเรียน
นอกเหนือจากเหตุผลที่ให้ไว้ในคำตอบอื่น ๆ สิ่งหนึ่งที่ฉันพบคือถ้าคนตัดไม้ของฉันไม่นิ่งหรือสุดท้าย:
...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);
public String toJson() {
GsonBuilder gsonBuilder = new GsonBuilder();
return gsonBuilder.create().toJsonTree(this).toString();
}
...
ในบางกรณี (เมื่อฉันใช้ไลบรารี Gson) ฉันจะได้รับข้อยกเว้น stackoverflow สถานการณ์เฉพาะของฉันคือการสร้างอินสแตนซ์ของคลาสที่มีตัวบันทึกขั้นสุดท้ายแบบไม่คงที่ จากนั้นเรียกใช้เมธอด toJson ซึ่งเรียกใช้ GsonBuilder:
...
DataSummary ds = new DataSummary(data);
System.out.println(ds.toJson());
...
จริงๆแล้วเครื่องตัดไม้แบบคงที่อาจเป็น "อันตราย" ได้เนื่องจากควรจะทำงานในบริบทคงที่ เมื่อมีสภาพแวดล้อมแบบไดนามิกเช่น OSGi อาจช่วยในการใช้เครื่องตัดไม้แบบไม่คงที่ เนื่องจากการใช้งานการบันทึกบางอย่างทำการแคชของคนตัดไม้ภายใน (AFAIK อย่างน้อยก็ log4j) ผลกระทบด้านประสิทธิภาพอาจเล็กน้อย
ข้อเสียเปรียบประการหนึ่งของเครื่องตัดไม้แบบคงที่คือ การรวบรวมขยะ (เมื่อใช้คลาสเพียงครั้งเดียวเช่นในระหว่างการเริ่มต้นคนตัดไม้จะยังคงเก็บไว้รอบ ๆ )
ตรวจสอบรายละเอียดเพิ่มเติม:
ดูสิ่งนี้ด้วย:
ตามข้อมูลที่ฉันอ่านจากอินเทอร์เน็ตเกี่ยวกับการทำให้คนตัดไม้เป็นแบบคงที่หรือไม่แนวทางปฏิบัติที่ดีที่สุดคือใช้ตามกรณีการใช้งาน
มีสองข้อโต้แย้งหลัก:
1) เมื่อคุณทำให้มันคงที่จะไม่เก็บขยะ (การใช้หน่วยความจำและประสิทธิภาพ)
2) เมื่อคุณไม่ทำให้มันคงที่มันจะถูกสร้างขึ้นสำหรับแต่ละอินสแตนซ์คลาส (การใช้หน่วยความจำ)
ดังนั้นเมื่อคุณสร้างคนตัดไม้สำหรับซิงเกิลตันคุณไม่จำเป็นต้องทำให้มันคงที่ เนื่องจากจะมีเพียงอินสแตนซ์เดียวจึงมีคนตัดไม้หนึ่งตัว
ในทางกลับกันหากคุณกำลังสร้างตัวบันทึกสำหรับโมเดลหรือคลาสเอนทิตีคุณควรกำหนดให้เป็นแบบคงที่เพื่อไม่ให้สร้างตัวบันทึกซ้ำ
คุณยังต้องมีตัวบันทึกแบบคงที่สำหรับคลาสแบบคงที่ภายใน