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

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

Java-разработчик 🧩
363
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 Ссылки

Еще по теме

Гибкое журналирование с помощью log4j

Log4j – это инструмент для журналирования с открытым исходным кодом, разработанный под эгидой глобального проекта Jakarta Apache. Он представляет собой набор API с помощью которых, разработчики могут вставлять в свой код выражения, которые выводят некоторую информацию (отладочную, информационную, сообщения об ошибках и т.д.), и конфигурировать этот вывод с помощью внешний конфигурационных файлов. В этой статье рассматриваются основные идеи, положенные в данный инструмент, а также будут затронуты некоторые интересные моменты, касающиеся написания демонстрационного web-приложения.

Аннотации в Java (java annotation types). Пример 1

Продолжаю серию статей о нововведениях в Java (начиная с версии 1.5). На этот раз разговор пойдет об аннотациях (annotation type).

Указатели и виртуальные функции в Java

В настоящее время в Интернете можно найти множество статей как о перспективности платформы Java, так и об её ограниченности. Многих программистов, только присматривающихся к Яве, могут отпугнуть частые заявления, типа: «низкое быстродействие», «отсутствие указателей» и т.д.

Блокировки

Одной из популярных функциональных возможностей библиотек J2SE 5.0 является добавление средств обеспечения параллельной работы. Предоставленные как часть JSR 166 эти средства обеспечивают развитые возможности программирования параллельных процессов, устраняющие необходимость использования разработчиками ключевого слова synchronized и связанных с ним блокировок. Среди предлагаемых ими функциональных возможностей присутствуют: поддержка блокировочных таймаутов, множественные переменные условия для одной блокировки, блокировки чтения/записи и способность прерывать поток, ожидающий снятия блокировки. Более подробную информацию по дополнительной поддержке блокировок можно найти в документации по пакету java.util.concurrent.locks.