Класс ResourceBundle - Вопросы
Всего: 6 вопросов
1. Что такое ResourceBundle в Java и как устроен properties-файл для него?
Что такое ResourceBundle в Java и как устроен properties-файл для него?
java.util.ResourceBundle — это набор локализованных ресурсов (строк и объектов), который Java загружает для нужной локали по базовому имени. Тексты интерфейса хранятся отдельно от кода, и новый язык добавляется новым файлом без перекомпиляции.
Properties-файл — текстовый файл, где каждая строка задаёт пару «ключ = значение»:
- строки, начинающиеся с
#или!, — комментарии; - пробелы вокруг
=игнорируются, вместо=можно писать:; - длинное значение переносится на следующую строку символом
в конце строки; - ключи принято группировать через точку:
label.button,message.welcome.
Все файлы набора содержат одни и те же ключи, переведённые для своей локали.
2. Как называются файлы одного набора ресурсов и как их загрузить методом ResourceBundle.getBundle()?
Как называются файлы одного набора ресурсов и как их загрузить методом ResourceBundle.getBundle()?
У всех файлов набора общее базовое имя, к которому через подчёркивание добавляются код языка и код страны: text.properties (базовый файл), text_ru_RU.properties, text_fr_CA.properties.
Набор загружает статический метод ResourceBundle.getBundle(baseName, locale), где baseName — базовое имя без суффиксов и без расширения:
ResourceBundle rb = ResourceBundle.getBundle("text", Locale.of("fr", "CA"));
Файлы ищутся в classpath, а не в рабочей папке: в Maven/Gradle — в src/main/resources. Если файл лежит в пакете, базовое имя указывается полностью через точки: getBundle("com.example.i18n.text", locale). Вызов без локали getBundle("text") использует Locale.getDefault().
3. В каком порядке ResourceBundle.getBundle() ищет файлы и почему для Locale.US может вернуться русский текст?
В каком порядке ResourceBundle.getBundle() ищет файлы и почему для Locale.US может вернуться русский текст?
Поиск идёт от самого точного имени к общему. Для запроса fr_CA при локали JVM по умолчанию ru_RU кандидаты такие:
text_fr_CA,text_fr— запрошенная локаль;text_ru_RU,text_ru— локаль по умолчанию;text— базовый файл.
Берётся первый найденный файл, а более общие становятся его родителями для недостающих ключей. Поэтому если нет text_en_US и text_en, но есть text_ru, запрос Locale.US на машине с русской локалью вернёт русский бандл, а не text.properties. Исключение — запрос Locale.ROOT: для него сразу берётся базовый файл.
Отключить шаг с локалью по умолчанию можно через ResourceBundle.Control.getNoFallbackControl(ResourceBundle.Control.FORMAT_DEFAULT) — это полезно на сервере, где локаль JVM не связана с языком пользователя. В именованных модулях перегрузки с Control бросают UnsupportedOperationException.
4. В какой кодировке ResourceBundle читает properties-файлы в Java 8 и в Java 9+?
В какой кодировке ResourceBundle читает properties-файлы в Java 8 и в Java 9+?
В Java 8 и раньше — в ISO-8859-1, поэтому кириллицу записывали escape-последовательностями uXXXX (утилитой native2ascii или настройкой IDE), иначе выводились «кракозябры».
С Java 9 (JEP 226) PropertyResourceBundle читает файлы в UTF-8, и кириллицу можно писать как есть. Если файл не является корректным UTF-8, он перечитывается как ISO-8859-1. Последовательности uXXXX работают во всех версиях, а прежнее поведение возвращает свойство -Djava.util.PropertyResourceBundle.encoding=ISO-8859-1. Утилита native2ascii из JDK 9 удалена.
Переход на UTF-8 касается только ResourceBundle: Properties.load(InputStream) по-прежнему читает ISO-8859-1. Для UTF-8 в Properties передают Reader: props.load(new InputStreamReader(in, StandardCharsets.UTF_8)).
5. Когда возникает MissingResourceException и как его избежать?
Когда возникает MissingResourceException и как его избежать?
MissingResourceException — непроверяемое исключение (наследник RuntimeException). ResourceBundle бросает его в двух случаях:
getBundle()не нашёл ни одного файла набора, включая базовый:Can't find bundle for base name labels, locale fr_CA;getString()илиgetObject()не нашёл ключ ни в файле, ни в его родителях:Can't find resource for bundle java.util.PropertyResourceBundle, key str9.nullпри этом не возвращается.
Чтобы избежать исключения, держите базовый файл без суффиксов (text.properties) со всеми ключами и проверяйте ключ методом containsKey(). Если файл существует, а исключение всё равно возникает, обычно виновато расположение: файл не попал в classpath или базовое имя указано без пакета.
6. Чем ListResourceBundle отличается от PropertyResourceBundle?
Чем ListResourceBundle отличается от PropertyResourceBundle?
Это две стандартные реализации абстрактного класса ResourceBundle:
PropertyResourceBundleчитает ресурсы из properties-файла (text_fr.properties), значения — толькоString. Подходит для текстов интерфейса: переводчики правят файлы без программиста.ListResourceBundleберёт ресурсы из Java-класса (class text_fr extends ListResourceBundle, методgetContents()возвращаетObject[][]) и хранит объекты любого типа: числа, массивы, иконки. Нестроковые значения читают черезgetObject().
Для каждого имени-кандидата getBundle() сначала ищет класс, затем properties-файл, поэтому при наличии и класса Messages_fr, и файла Messages_fr.properties загружается класс. Метод getStringArray() с properties-файлом не работает: значение там всегда строка, и будет ClassCastException.