วิธีที่ดีที่สุดในการเริ่มต้นสมาชิกสแตติกที่ซับซ้อนใน Java คืออะไร?

วัตถุประสงค์ของฉันคือการมีวัตถุ Properties แบบคงที่ส่วนตัวในชั้นเรียนของฉัน เพื่อทำหน้าที่เป็นค่าเริ่มต้นเมื่อสร้างวัตถุ Properties อื่น ๆ ที่จำเป็นสำหรับแอปพลิเคชันของฉัน การใช้งานปัจจุบันมีลักษณะดังนี้:

public class MyClass {
    private static Properties DEFAULT_PROPERTIES = new Properties();

    static {
        try {
           DEFAULT_PROPERTIES.load(
               MyClass.class.getResourceAsStream("myclass.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 }

ดูแล้วมันก็ใช้ได้แต่รู้สึกไม่โอเค

คุณจะทำมันได้อย่างไร?


person Igor    schedule 08.01.2010    source แหล่งที่มา


คำตอบ (3)


โดยพื้นฐานแล้วมีสองวิธี วิธีแรกคือการใช้บล็อกแบบคงที่ตามที่คุณแสดง (แต่จากนั้นด้วย ExceptionInInitializerError แทน RuntimeException) วิธีที่สองคือการใช้วิธีการคงที่ซึ่งคุณเรียกใช้ทันทีเมื่อมีการประกาศ:

private static Properties DEFAULT_PROPERTIES = getDefaultProperties();

private static Properties getDefaultProperties() {
    Properties properties = new Properties();
    try {
        properties.load(MyClass.class.getResourceAsStream("myclass.properties"));
    } catch (IOException e) {
        throw new ConfigurationException("Cannot load properties file", e);
    }
    return properties;
}

ConfigurationException สามารถเป็นคลาสที่คุณกำหนดเองซึ่งขยาย RuntimeException

โดยส่วนตัวแล้วฉันชอบบล็อก static มากกว่าเพราะมันไม่สมเหตุสมผลเลยที่จะมีเมธอดที่ถูกดำเนินการ เพียงครั้งเดียว ในชีวิต แต่ถ้าคุณปรับโครงสร้างวิธีการใหม่เพื่อให้ใช้ชื่อไฟล์และสามารถนำมาใช้ซ้ำได้ทั่วโลก นั่นก็จะเป็นที่ต้องการมากกว่า

private static Properties DEFAULT_PROPERTIES = SomeUtil.getProperties("myclass.properties");

// Put this in a SomeUtil class.
public static Properties getProperties(String filename) {
    Properties properties = new Properties();
    try {
        properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(filename));
    } catch (IOException e) {
        throw new ConfigurationException("Cannot load " + filename, e);
    }
    return properties;
}
person BalusC    schedule 08.01.2010
comment
สิ่งนี้เหมาะกับปัญหาของฉันจริงๆ เพราะว่าฉันจะสร้างคลาสเพิ่มเติมด้วยรูปแบบเดียวกัน ดังนั้นจึงสมเหตุสมผลที่จะสร้างคลาสนามธรรมและเติมด้วยเมธอด getProperties() เพื่อให้สามารถนำกลับมาใช้ในคลาสย่อยทั้งหมดของฉันได้ มีข้อมูลมาก ขอบคุณ! - person Igor; 08.01.2010
comment
โปรดทราบว่าฉันเปลี่ยนวิธีการโหลดไฟล์คุณสมบัติโดยใช้ Thread#getContextClassLoader() อย่าลืมแก้ไขสิ่งนี้ในโค้ดของคุณด้วย - person BalusC; 08.01.2010
comment
สิ่งนี้จะโหลดทรัพยากรในแพ็คเกจเดียวกันกับคลาสที่เรียก getProperties() หรือไม่ - person Igor; 08.01.2010
comment
ฉันไม่แน่ใจว่าฉันเข้าใจคุณไหม ไม่ว่าจะด้วยวิธีใดก็เป็นเพียงแพ็คเกจที่ไม่ขึ้นอยู่กับแพ็คเกจ คุณสามารถระบุแพ็คเกจในชื่อไฟล์ได้ วิธีที่ได้รับการปรับปรุงนั้นไม่ขึ้นอยู่กับคลาสและใช้ประโยชน์จาก classloader ซึ่งโหลดคลาสการเรียกไว้แล้ว วิธีนี้ช่วยให้คุณมั่นใจได้ว่าทรัพยากรจะไม่ส่งคืนค่าว่าง ซึ่งอาจเกิดขึ้นได้หากคลาสที่เรียกไม่ได้โหลดโดย classloader ของเธรด - person BalusC; 08.01.2010
comment
ฉันหมายถึงว่า org.example.MyClass.class.getResourceAsStream("myclass.properties") จะเปิดทรัพยากร ROOT/org/example/myclass.properties ในขณะที่ใช้ ClassLoader มันจะค้นหาทรัพยากรในไดเรกทอรี ROOT/ ฉันผิดหรือเปล่า? - person Igor; 08.01.2010
comment
โอ้ ทางนี้.. ใช่ เพียงระบุแพ็คเกจในชื่อไฟล์ - person BalusC; 08.01.2010

แทนที่จะเป็น RuntimeException ทั่วไป ฉันจะโยน ExceptionInInitializerError ซึ่งกล่าวถึงจุดประสงค์นี้โดยเฉพาะ จากเอกสารประกอบ API: "ส่งสัญญาณว่ามีข้อยกเว้นที่ไม่คาดคิดเกิดขึ้นในตัวเริ่มต้นแบบคงที่"

person jarnbjo    schedule 08.01.2010
comment
โอ้ ฉันไม่รู้ว่า ขอบคุณสำหรับคำใบ้! - person Igor; 08.01.2010
comment
@jarnbjo ฉันคิดว่ามันจะมีประโยชน์ถ้าคุณให้ลิงก์ไปยังเอกสาร API (ของ ExceptionInitializer) ด้วย: java.sun.com/j2se/1.5.0/docs/api/java/lang/ - person sateesh; 08.01.2010
comment
@sateesh: หากนักพัฒนา Java ไม่สามารถค้นหาคลาสในเอกสารประกอบ API โดยไม่มีลิงก์ในคำตอบของฉัน ถึงเวลาที่เขาจะต้องเรียนรู้วิธีการทำ - person jarnbjo; 08.01.2010

ดูเหมือนว่าฉันจะยอมรับได้ โหลดใน static Initialiser ซึ่งจะถูกเรียกเมื่อมีการอ้างอิงคลาสเท่านั้น และจะถูกเรียกเพียงครั้งเดียวเท่านั้น ฉันชอบมัน. สิ่งเดียวที่ฉันทำคือทำให้มัน final

นอกจากข้อยกเว้นแล้ว ฉันจะพยายามหลีกเลี่ยงสิ่งนั้น (ฉันนึกในใจว่าคุณควรหลีกเลี่ยงข้อยกเว้นในตัวเริ่มต้นประเภทเหล่านั้น แต่ฉันอาจผิดในเรื่องนั้น)

person Noon Silk    schedule 08.01.2010