Главная > Java сниппеты > Как хранить настройки java программ?

Тема Зацепин
268

Java-разработчик 🧩
235
1 минуту

Как хранить настройки java программ?

Этот вопрос задает себе каждый разработчик любого серьезного приложения. Классическим решением этой задачи является использование класса Properties. Этот класс поддерживает коллекции свойств (properties) вида ключ/значение, где ключи и значения являются строками. Наличие методов сохранения и чтения коллекций в файлах, упрощает организацию физического хранения данных. Несмотря на удобство и простоту использования данного класса хочется обратить ваше внимание, что класс Properties является наследником устаревшего класса Hashtable [1]. Именно по этому рекомендуется использовать класс HashMap, который является аналогом Hashtable.

Добавлено : 6 Nov 2008, 16:47

Для доступа к настройкам программы создадим класс AppSettings. Причем в блоке инициализации статических членов класса будет вызываться private конструктор данного класса. При этом создается единственный экземпляр данного объекта в статическую переменную SINGLETON при первом вызове из основного кода программы. Код, реализующий эту методику имеет вид:

public class AppSettings {
private AppSettings() {
fHashMap = new HashMap();
}
// . . .

private HashMap fHashMap;
private static AppSettings SINGLETON;
static {
SINGLETON = new AppSettings();
}
}

Таким образом к единственному экземпляру данного класса можно получить доступ из любого модуля программы, что напоминает глобальные переменные в других языках программирования. Коллекция HashMap позволяет хранить различные объекты, но мы пока ограничимся только строковыми. Методы доступа к данным могут иметь вид:

// Извлечение объекта из коллекции
public static Object get(String key) {
return SINGLETON.fHashMap.get(key);
}

// Извлечение объекта из коллекции
// при отсутствии данных возвращается значение по умолчанию
public static Object get(String key, Object deflt) {
Object obj = SINGLETON.fHashMap.get(key);
if (obj == null) {
return deflt;
} else {
return obj;
}
}

// Для упрощения извлечения данных типа int
public static int getInt(String key, int deflt) {
Object obj = SINGLETON.fHashMap.get(key);
if (obj == null) {
return deflt;
} else {
return new Integer((String) obj).intValue();
}
}

// Добавление объекта в коллекцию
public static void put(String key, Object data) {
// prevent null values. Hasmap allow them
if (data == null) {
throw new IllegalArgumentException();
} else {
SINGLETON.fHashMap.put(key, data);
}
}

Раз уж мы отказались от использования класса Properties, то изменим формат хранения объектов коллекции на более прогрессивный xml формат. Структура xml файла будет иметь вид:

xmlversion = '1.0'?>key="MainFrame.height">319key="MainFrame.width">424key="LookAndFeel">com.sun.java.swing.plaf.motif.MotifLookAndFeel

Данная структура позволит нам в будущем хранить не только значения вида ключ/значение, но и другие типы объектов. Пока же, мы ограничимся строками, аналогично классу Properties. Код построения DOM дерева заданной структуры и трансформации в xml файл будет иметь вид:

public static boolean save(File file) throws Exception {
// Создаем новое DOM дерево
DOMImplementation domImpl = new DOMImplementationImpl();
Document doc = domImpl.createDocument
(null, "app-settings", null);
Element root = doc.getDocumentElement
();
Element propertiesElement = doc.createElement
("properties");
root.appendChild
(propertiesElement);
Set set = SINGLETON.fHashMap.keySet
();
if (set != null) {
for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
String key = iterator.next().toString();
Element propertyElement = doc.createElement
("property");
propertyElement.setAttribute
("key", key);
Text nameText = doc.createTextNode
(get(key).toString());
propertyElement.appendChild
((Node) nameText);
propertiesElement.appendChild
(propertyElement);
}
}
// Сериализируем DOM дерево в файл
DOMSerializer serializer = new DOMSerializer();
serializer.serialize
(doc, file);
return true;
}

Класс сериализации DOM дерева позаимствован в [2]. Для обратной операции чтения данных в коллекцию создадим следующий метод:

public static boolean load(File file) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder
();
Document doc = builder.parse
(file);
if (doc == null) {
throw new NullPointerException();
}
NodeList propertiesNL = doc.getDocumentElement().getChildNodes();
if (propertiesNL != null) {
for (int i = 0; (i < propertiesNL.getLength()); i++) {
if (propertiesNL.item(i).getNodeName().equals("properties")) {
NodeList propertyList = propertiesNL.item(i).getChildNodes();
for (int j = 0; j < propertyList.getLength(); j++) {
NamedNodeMap attributes = propertyList.item(j).getAttributes();
if (attributes != null) {
Node n = attributes.getNamedItem("key");
NodeList childs = propertyList.item
(j).getChildNodes();
if (childs != null) {
for (int k = 0; k < childs.getLength(); k++) {
if (childs.item(k).getNodeType() == Node.TEXT_NODE) {
put(n.getNodeValue(), childs.item(k).getNodeValue());
}
}
}
}
}
}
}
return true;
} else {
return false;
}
}

А пример вызова методов класса AppSettings в теле программы, показан в следующем участке кода:

File file = new File(propDir, "settings.xml");
try {
AppSettings.clear();
AppSettings.load
(file);
String lnfName = UIManager.getLookAndFeel
().getClass().getName();
if (AppSettings.get(LF_KEY, lnfName) != lnfName) {
UIManager.setLookAndFeel(
(
String) AppSettings.get(LF_KEY, lnfName));
SwingUtilities.updateComponentTreeUI
(MainFrame.this);
}

this.setSize(new Dimension(
AppSettings.getInt(WIDTH_KEY, getWidth()),
AppSettings.getInt
(HEIGHT_KEY, getHeight())
))
;
} catch (Exception e) {
e.printStackTrace();
}

Как видно из приведенного кода, все достаточно тривиально. Просто вызываем нужный метод класса AppSettings создавать экземпляр которого не требуется. Можно реализовать еще пару методов для извлечения часто используемых типов данных для удобства использования, например getString().

Автор: Сергей Бердачук

Теги: javaproperties

Еще от автора

Применение WeakHashmap для списков слушателей

В статье от 11мая 1999 года Reference Objects были описаны основные идеи применения ссылочных объектов, но не приводилось детального описания. Данная статья позволит вам получить больше сведений, касающихся данной темы. В основном ссылочные объекты применяются для косвенных ссылок на память необходимую объектам. Ссылочные объекты хранятся в очереди (класс ReferenceQueue), в которой отслеживается доступность ссылочных объектов. Исходя из типа ссылочного объекта, сборщик мусора может освобождать память даже тогда, когда обычные ссылки не могут быть освобождены.

Заставки в Mustang

Согласно определению, данному в Wikipedia, заставка - это компьютерный термин, обозначающий рисунок, появляющийся во время загрузки программы или операционной системы. Заставка для пользователя является визуальным отображением инициализации программы. До выхода версии Java SE 6 (кодовое название Mustang) единственной возможностью применения заставки было создание окна, во время запуска метода main, и размещение в нем картинки. Хотя данный способ и работал, но он требовал полной инициализации исполняемой Java среды до появления окна заставки. При инициализации загружались библиотеки AWT и Swing, таким образом, появление заставки задерживалось. В Mustang появился новый аргумент командной строки, значительно облегчающий использование заставок. Этот способ позволяет выводить заставку значительно быстрее до запуска исполняемой Java среды. Окончательное добавление данной функциональности находится на рассмотрении в JCP.

Совмещение изображений

1 Введение 2 Правила визуализации и пример 3 Совмещение изображений в оперативной памяти 4 Постепенное исчезновение изображения 5 Ссылки и дополнительная информация

Еще по теме

Применение WeakHashmap для списков слушателей

В статье от 11мая 1999 года Reference Objects были описаны основные идеи применения ссылочных объектов, но не приводилось детального описания. Данная статья позволит вам получить больше сведений, касающихся данной темы. В основном ссылочные объекты применяются для косвенных ссылок на память необходимую объектам. Ссылочные объекты хранятся в очереди (класс ReferenceQueue), в которой отслеживается доступность ссылочных объектов. Исходя из типа ссылочного объекта, сборщик мусора может освобождать память даже тогда, когда обычные ссылки не могут быть освобождены.

Заставки в Mustang

Согласно определению, данному в Wikipedia, заставка - это компьютерный термин, обозначающий рисунок, появляющийся во время загрузки программы или операционной системы. Заставка для пользователя является визуальным отображением инициализации программы. До выхода версии Java SE 6 (кодовое название Mustang) единственной возможностью применения заставки было создание окна, во время запуска метода main, и размещение в нем картинки. Хотя данный способ и работал, но он требовал полной инициализации исполняемой Java среды до появления окна заставки. При инициализации загружались библиотеки AWT и Swing, таким образом, появление заставки задерживалось. В Mustang появился новый аргумент командной строки, значительно облегчающий использование заставок. Этот способ позволяет выводить заставку значительно быстрее до запуска исполняемой Java среды. Окончательное добавление данной функциональности находится на рассмотрении в JCP.

Использование потоков

1 Введение 2 Работа с выражениями типа Boolean 3 Класс JoptionPane 4 Приложение-счетчик 5 Ссылки

Перехват необрабатываемых исключений

В статье от 16 марта 2004 года Best Practices in Exception Handling были описаны приемы обработки исключений. В данной статье вы изучите новый способ обработки исключений при помощи класса UncaughtExceptionHandler добавленного в J2SE 5.0.

Использование класса LinkedHashMap

1 Введение 2 Сортировка хэш-таблицы 3 Копирование таблицы 4 Сохранение порядка доступа к элементам 5 Ссылки

Сказ про кодировки и java

С кодировками в java плохо. Т.е., наоборот, все идеально хорошо: внутреннее представление строк – Utf16-BE (и поддержка Unicode была с самых первых дней). Все возможные функции умеют преобразовывать строку из маленького регистра в большой, проверять является ли данный символ буквой или цифрой, выполнять поиск в строке (в том числе с регулярными выражениями) и прочее и прочее. Для этих операций не нужно использовать какие-то посторонние библиотеки вроде привычных для php mbstring или iconv. Как говорится, поддержка многоязычных тестов “есть в коробке”. Так откуда берутся проблемы? Проблемы возникают, как только строки текста пытаются “выбраться” из jvm (операции вывода текста различным потребителям) или наоборот пытаются в эту самую jvm “залезть” (операция чтения данных от некоторого поставщика).