Можно ли получить доступ к значению переменной статического списка по имени класса, который является статическим списком только для чтения?

1

Вот мой код.

public class PropertyLoader {

    private Properties appProperties;

    /**
     * The instance.
     */
    private static PropertyLoader inst = null;

    /**
     * Instantiates a new property data loader.
     */
    private PropertyLoader() {
        try
        {
            appProperties = new Properties();
            appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public static PropertyLoader getInstance() {
        if (inst == null) {
            inst = new PropertyLoader();
        }
            return inst;
        }
    }

    public String getPropertyAPP(String key) {
        return appProperties.getProperty(key);
    }

}

Синхронизация необходима для метода getPropertyAPP: это одноэлементный режим, поэтому многие потоки могут одновременно обращаться к одному экземпляру и вызывать его.

Может ли кто-нибудь предложить мне правильный путь?

Теги:
static

4 ответа

3
Лучший ответ

вы можете использовать следующее решение

public class PropertyLoader {

        private Properties appProperties;

    /** The instance. */
    private static PropertyLoader inst = null;

    static{
        inst = new PropertyLoader();
    }

    /**
     * Instantiates a new property data loader.
     */
    private PropertyLoader() {
            try
            {
                appProperties = new Properties();
                appProperties.load(this.getClass().getClassLoader().getResourceAsStream("app.properties"));
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
    }

    public static PropertyLoader getInstance() {
        return inst;
    }


    public String getPropertyAPP(String key) {
        return appProperties.getProperty(key);
    }
}
1

Более простым решением, которое также является безопасным потоком, является использование статической инициализации для инициализации статического поля.

public class AppProperties {
    private static final Properties appProperties;
    static {
        try {
            appProperties = new Properties();
            appProperties.load(AppProperties.class
                      .getClassLoader().getResourceAsStream("app.properties"));
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public String get(String key) {
        return appProperties.getProperty(key);
    }

    public String get(String key, String defaultValue) {
        return appProperties.getProperty(key, defaultValue);
    }
}
  • 0
    Эй, Питер, IOException наверняка приведет к сломанному приложению?
  • 0
    @MrWiggles, если значения по умолчанию не являются разумными. В противном случае я бы обернул IOE AssertionError
0

Несколько проблем с кодом:

(a) Вы уверены, что вам нужна ленивая инициализация? Стоимость инициализации должна быть заметной, и вероятность того, что ресурс никогда не используется, должна быть отличной от нуля. Кроме того: может быть предпочтительнее сбой во время запуска программы, а не в какой-то неопределенный момент позже, когда ресурс будет впервые доступен. Это действительно зависит от вашего приложения.

(b) Один из способов реализации ленивой инициализации - использовать правильную версию двойной проверки блокировки (ключевое слово volatile является существенным):

private static volatile PropertyLoader inst;
...
public static PropertyLoader getInstance() {
    if (inst == null) {
        synchronized(PropertyLoader.class) {
            if (inst == null) {
                inst = new PropertyLoader();
            }
        }
    }
    return inst;
} 

В этой статье, посвященной википедиям, объясняется, почему это работает (начиная с Java 5, но не раньше): http://en.wikipedia.org/wiki/Double-checked_locking

(c) Захват исключений и просто их регистрация в большинстве случаев ошибочны. В вашем случае никакое свойство никогда не будет возвращено из getPropertyAPP. Это может быть нормально, если наличие свойств явно объявлено необязательным.

0

В вашем методе getInstance() происходит массовое состояние гонки. Если несколько потоков обращаются к getInstance() одновременно, вы создадите несколько экземпляров и назначаете их по очереди статической переменной. Учитывая то, что вы здесь делаете, это не вызовет каких-либо логических проблем, но это означает, что вы делаете больше работы, чем необходимо.

Я рекомендую вам немного прочитать о шаблоне Singleton, почему это плохо, и как реализовать его безопасным способом в Java.

Но, короче говоря, не используйте шаблон Singleton, он отвратительно сломан и сделает любой код, который использует этот объект тесно связан и будет препятствовать вашей способности делать какие-либо изолированное тестирование.

  • 0
    Возможно, вы могли бы предложить альтернативу шаблону Singleton для Properties . Кстати: шаблон не нарушен - многие его реализации в Java не работают.
  • 0
    Паттерн Синглтона, представленный здесь, с классами, знающими, где найти Синглтон , сломан - Эрик Гамма даже заявил, что его никогда не должно было быть в книге GoF. Я бы порекомендовал создать его экземпляр при запуске приложения вручную или с помощью инфраструктуры DI и внедрить его при необходимости.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню