Properties

Java Collections
1 уровень , 9 лекция
Открыта

— Сегодня мы изучаем еще одну новую и интересную тему – свойства (properties).

Properties - 1

В Java принято делать программы гибкими и легко настраиваемыми. Иногда еще говорят легко конфигурируемыми (от конфигурация).

Например, твоя программа раз в час копирует файлы из некоторой директории, архивирует их и отсылает тебе на email. Для этого программе надо знать директорию, откуда брать файлы и email, куда их посылать. Такие данные принято хранить не в коде программы, а в отдельных файлах свойств – properties-файлах.

Данные в таком файле хранятся в виде пар ключ-значение, разделенные знаком равно.

Пример
Файл data.properties
directory=c:/text/downloads
email=zapp@javarush.ru

Слева от знака равно – имя (ключ), справа – значение.

— Т.е. это что-то типа текстового представления HashMap?

— В общем-то, да.

Для удобной работы с такими файлами в Java есть специальный класс – Properties. Класс Properties унаследован от Hashtable<Object,Object>. Его даже можно рассматривать как HashTable, который умеет загружать себя из файла.

Вот его методы:

Метод Описание
void load(Reader reader) Загружает свойства из файла, представленного объектом Reader
void load(InputStream inStream) Загружает свойства из файла, представленного объектом InputStream
void loadFromXML(InputStream in) Загружает свойства из XML-файла
Object get(Object key) Возвращает значение по ключу. Метод унаследован от HashTable
String getProperty(String key) Возвращает значение свойства (строку) по ключу
String getProperty(String key, String defaultValue) Возвращает значение свойства по ключу или defaultValue, если такого ключа нет
Set<String> stringPropertyNames() Возвращает список всех ключей

Т.е. фактически тебе нужно выполнить всего две операции – загрузить в объект Properties данные из какого-нибудь файла, а затем получить эти свойства с помощью метода getProperty(). Ну и не забывай, что можешь пользоваться объектом Properties как HashMap.

Вот тебе пример:

Код
//файл, который хранит свойства нашего проекта
File file = new File("c:/data.properties");

//создаем объект Properties и загружаем в него данные из файла.
Properties properties = new Properties();
properties.load(new FileReader(file));

//получаем значения свойств из объекта Properties
String email = properties.getProperty("email");
String directory = properties.getProperty("directory");

//получаем числовое значение из объекта Properties
int maxFileSize = Integer.parseInt(properties.getProperty("max.size", "10000"));

— Ага. Т.е. мы создаем объект Properties, затем передаем в него файл. В метод load, а затем просто вызываем getProperty. Так?

— Ага.

— А ты еще говорил, что им можно пользоваться как HashMap? Что ты имел в виду?

— Класс Properties унаследован от Hashtable, а это – тот же HashMap, просто все методы его синхронизированы. Вот так можно просто вывести на экран все значения из файла свойств:

Код
//получаем файл со свойствами
File file = new File("c:/data.properties");

//создаем объект Properties и загружаем в него данные из файла.
Properties properties = new Properties();
properties.load(new FileReader(file));

//проходимся по всем ключам и печатаем все их значения на консоль
for (String key : properties.stringPropertyNames())
{
 System.out.println(properties.get(key));
}

— Ага. Вроде все стало на свои места. Спасибо, Риша, буду пользоваться такой крутой штукой.

Комментарии (99)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
{Java_Shark} Уровень 36
15 января 2025
++
Suzuya Jūzō Уровень 46
17 июня 2023
Сегодня мы изучаем еще одну новую и интересную тему – свойства (properties) Да в каком месте она новая то? В двух предыдущих квестах уже была...
wan-derer.ru Уровень 40
17 февраля 2023
Надо уточнить что файлы .properties не поддерживают кириллицу! Они формата ISO-чего-то-там, только базовая латиница. Так что пример на самом верху неправильный. Если надо в файлах хранить кириллицу, используйте современные форматы: JSON, YAML.... Правда, для их парсинга придётся использовать дополнительную библиотечку, например, Jackson.
BucketOnHead Уровень 51 Expert
28 марта 2023
Да, это правда. Файлы формата .properties используют кодировку ISO-8859-1 (также известную как Latin-1) по умолчанию, которая не поддерживает символы кириллицы и других не-латинских алфавитов. Для хранения текста на не-латинских языках рекомендуется использовать более современные форматы, такие как JSON, YAML или XML. В этих форматах можно указать любую кодировку для хранения текста, включая UTF-8, которая широко используется в мировом интернете и поддерживает множество языков, включая кириллицу. Для работы с файлами в таких форматах, как JSON и YAML, можно использовать соответствующие библиотеки парсинга, такие как Jackson, Gson, SnakeYAML и др.
Петрович Уровень 36
28 августа 2022
Друзья, а почему мне null вернуло?
Alexey Уровень 24
6 сентября 2022
Содержимое файла какое?
Петрович Уровень 36
7 сентября 2022
не пустные....directory=c:/text/downloads email=zapp@javarush.ru .. как в примере
Alexey Уровень 24
7 сентября 2022
Сразу не заметил. Расширение файла должно быть не .txt ,а .properties
Петрович Уровень 36
9 сентября 2022
ха точно, спасибо=)
Евгений Уровень 38
10 декабря 2022
Ты вроде load не сделал
Серега Батенин Уровень 12
9 января 2023
это прям важный момент? ТО есть с файла именно только с таким расширением будет рабтоать, а с любым другим нет?
4 декабря 2024
а где загрузка файла? Пустая проперти, нужно загрузить файл, который тоже не создал
Lipovskyi Volodymyr Уровень 36
12 августа 2022
Ріша, та ми же вивчили вже Properties на останніх рівнях у JavaCore, як і більшість Patterns - "Почитайте у вікі про це"🤣
Ilia lenskii Уровень 32
3 июля 2022
Что касается примеров кода, то есть вот это getResourceAsStream + там же ссылка на docs.oracle.com

MyClass.getResourceAsStream("my.properties");
Где MyClass имя вашего класса, далее class и вызов непосредственно getResourceAsStream У меня это выглядит вот так вот

 InputStream inpPror = Myprop.class.getResourceAsStream("../prp.properties");        
 if(inpPror != null)  {
            Properties properties = new Properties();
            properties.load(inpPror);
}
Экономия на спичках
Артём Уровень 28
21 февраля 2022
а чем это отличается от сериализации?
Anonymous #3161756 Уровень 40
17 февраля 2023
Собственно ни чем, просто видимо готовый инструмент со своими фишками)
LuneFox Уровень 41 Expert
19 декабря 2021
Как мёд для ушей (глаз), я тоже все настраиваемые параметры всегда хранил в отдельных классах, чтобы не выискивать их в коде (сам додумался), а тут даже специальный файлик с ними забубенили.
Alukard Уровень 37 Expert
24 декабря 2021
Ты что тут забыл, иди на работу уже)
LuneFox Уровень 41 Expert
24 декабря 2021
Сарказм принят)
Роман Кончалов Уровень 28 Expert
19 января 2022
Какие, например, параметры?
LuneFox Уровень 41 Expert
19 января 2022
Да какие угодно. Например, дефолтный размер окна, или шрифт, который исползует интерфейс, или путь к папке, откуда программа по умолчанию берёт файлы для работы.
Роман Кончалов Уровень 28 Expert
20 января 2022
Но ведь если эти параметры используются только в одно месте, то достаточно объявить их в начале целевого класса как private final. Или были какие-то параметры, которые в нескольких местах использовались?
LuneFox Уровень 41 Expert
20 января 2022
Я про то и говорю, что все параметры, которые могли бы быть записаны, как private final в куче разных классов я просто беру и выношу в отдельный класс с public static final полями, чтобы потом не искать их внутри кода в разных местах. Например, когда писал игры здесь, все строки, которые выводятся на экран, хранил в отдельном классе Strings. Например:

public static final String GAME_OVER_MESSAGE = "Вы проиграли!";
И если где-то вдруг хотел поправить описание или фразу, я просто лез в Strings, а не искал их в куче функционального кода с механикой игры. Никто не мешает хранить разные настраиваемые параметры разных классов точно так же.
Сергей Уровень 22
9 февраля 2022
а еще он хранится отдельно от собранного проекта, как можно хранить и иные конфо файлы. И поэтому их можно менять в любое время, если у тебя не хардкодед конечно же кругом в проекте.
Hidden #213 Уровень 48
26 февраля 2022
Нет, тебе точно пора уже на работу))) Я почти на том же уровне, но нифига не понимаю о чём вы говорите. Какие-то настраиваемые final параметры и специальный файл для них. Что?! Зачем?! 😅 И ты ещё говоришь, что сам к этому пришёл, без этой лекции...
LuneFox Уровень 41 Expert
26 февраля 2022
Дык чего тут особенного, тема лекции как раз про это самое :) Пока я не мог пользоваться properties, их роль заменял отдельный класс со статическими переменными. Например, в properties можно положить такие данные:

game.message.start=Игра началась!
game.message.finish=Игра закончилась!
А потом подгружать этот файлик и обращаться к полям properties. Я делал так прямо в классе:

public static final String GAME_MESSAGE_START = "Игра началась!";
public static final String GAME_MESSAGE_FINISH = "Игра закончилась!";
Ну, и обращался не так

printMessage(properties.get("game.message.start"));
А вот так

printMessage(Strings.GAME_MESSAGE_START);
Только и всего :) А сам я к этому пришёл по нужде, потому что устал искать строки с текстом в куче кода, чтобы исправить опечатку или что-то перефразировать. Тем более если строк много в разных классах.
Ars Уровень 41
15 ноября 2021
Инфа по задаче: Среднее количество попыток для этой задачи 2.24. Всего эту задачу решили 7291 учеников.
LuneFox Уровень 41 Expert
19 декабря 2021
Всё хорошо, только это не задача, а лекция.
Ars Уровень 41
19 декабря 2021
От блин. Но в задачу копировать не буду. Уже не актуальная инфа.
Anonymous #2620027 Уровень 47
13 ноября 2021
Properties уже разбирались в Core. Что Collections, что Multithreading основательно разбавлены повторением пройденного материала... В большинстве случаев, бессистемно.
LuneFox Уровень 41 Expert
19 декабря 2021
Я даже рад этому, потому что курс прохожу медленно, и всё забывается. Пока мой мозг чувствует сопротивление при решении задач, курс всё делает верно.
Ars Уровень 41
19 декабря 2021
Чтобы не забывалось, это надо использовать. И/или конспектировать. По идее так и заявлено, что в курсе много задачи и поэтому, всё хорошо запомнится. Только увы, на многие либо нет задач вообще, либо их пара штук. Вот если бы те же properties нет нет, да и всплывали бы в задачах, то они бы и не были забыты. А вот такое повторение теории без прилагающейся практики не спасёт ситуацию. Всё равно забудется, если не использовать.
LuneFox Уровень 41 Expert
19 декабря 2021
Ещё кстати хорошая практика для запоминания - это чётко понимать, что и как происходит, тогда и заучивать насильно ничего не придётся. Не знаю, какой пример даже привести. Например, если однажды выучить последовательность цифр от 1 до 10, то не нужно для каждого этажа в 10-этажном доме запоминать, какой находится выше, а какой ниже, а ещё отдельно помнить, что ниже 1 этажа и выше 10 этажа этажей нет, ты просто пользуешься здравым смыслом. А забыть здравый смысл куда сложнее, чем таблицу с информацией :)
Ars Уровень 41
19 декабря 2021
Понимать - не значит запомнить. Я могу прекрасно понять, как работает какой-нибудь LinkedHashMap, понять какие у него методы, чем он отличается от обычных HashMap и LinkedList. Но если я его не использовал достаточное время чтобы он отложился у меня в голове, то когда он мне понадобится, я про просто не вспомню. Учитывая, что разных классов только в JDK, наверное, сотни и есть ещё десятки фреймвороков со своими классами, то какими здравомысленными эти классы не были просто понять их чтобы запомнить - не выйдет.
LuneFox Уровень 41 Expert
19 декабря 2021
Тут уж не поспоришь. Помнить подробности применения сотен классов с тысячами методов просто нереально.