Преобразование java.util.Properties в HashMap <String, String>
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties
является реализацией java.util.Map
, а конструктор java.util.HashMap
получает параметр типа Map
. Итак, почему это должно быть преобразовано явно?
Ответы
Ответ 1
Это связано с тем, что Properties
extends Hashtable<Object, Object>
(что, в свою очередь, реализует Map<Object, Object>
). Вы пытаетесь передать это в Map<String, String>
. Поэтому он несовместим.
Вам нужно передать свойства строки по одному на вашу карту...
Например:
for (final String name: properties.stringPropertyNames())
map.put(name, properties.getProperty(name));
Ответ 2
Эффективный способ сделать это - просто привести к общей карте следующим образом:
Properties props = new Properties();
Map<String, String> map = (Map)props;
Это преобразует Map<Object, Object>
в необработанную карту, которая является "ok" для компилятора (только предупреждение). Как только у нас будет сырой Map
, он будет отбрасываться на Map<String, String>
, который также будет "хорошо" (другое предупреждение). Вы можете игнорировать их с помощью аннотации @SuppressWarnings({ "unchecked", "rawtypes" })
Это будет работать, потому что в JVM объект не имеет общего типа. Родовые типы - всего лишь трюк, который проверяет вещи во время компиляции.
Если какой-либо ключ или значение не является строкой, это приведет к ошибке ClassCastException
. При текущей реализации Properties
это очень маловероятно, если вы не используете изменяемые методы вызова из супер Hashtable<Object,Object>
Properties
.
Итак, если вы не делаете неприятные вещи с помощью экземпляра Properties, это способ пойти.
Ответ 3
Вы можете использовать Google Guava:
com.google.common.collect.Maps.fromProperties(Свойства)
Ответ 4
Как насчет этого?
Map properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);
Вызывает предупреждение, но работает без итераций.
Ответ 5
Способ Java 8:
properties.entrySet().stream().collect(
Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue().toString()
)
);
Ответ 6
Properties
реализует Map<Object, Object>
- not Map<String, String>
.
Вы пытаетесь вызвать этот конструктор:
public HashMap(Map<? extends K,? extends V> m)
... с K
и V
как String
.
Но Map<Object, Object>
не является Map<? extends String, ? extends String>
... он может содержать нестрочные ключи и значения.
Это будет работать:
Map<Object, Object> map = new HashMap<Object, Object>();
... но это было бы не так полезно для вас.
В принципе, Properties
никогда не должен был быть подклассом HashTable
... что проблема. Начиная с v1, он всегда мог хранить нестрочные ключи и значения, несмотря на то, что это было против намерения. Если бы композиция использовалась вместо этого, API мог бы работать только со строковыми ключами/значениями, и все было бы хорошо.
Вам может понадобиться что-то вроде этого:
Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
map.put(key, properties.getProperty(key));
}
Ответ 7
Я бы использовал следующий Guava API: com.google.common.collect.Maps # fromProperties
Properties properties = new Properties();
Map<String, String> map = Maps.fromProperties(properties);
Ответ 8
Если вы знаете, что ваш объект Properties
содержит только записи <String, String>
, вы можете прибегнуть к необработанному типу:
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);
Ответ 9
Проблема заключается в том, что Properties
реализует Map<Object, Object>
, тогда как конструктор HashMap
ожидает Map<? extends String, ? extends String>
.
Этот ответ объясняет это (совершенно противоречивое) решение. Короче: до Java 5, Properties
реализовано Map
(так как тогда не было никаких дженериков). Это означает, что вы можете поместить любой Object
в объект Properties
. Это все еще находится в предложении:
Поскольку Properties
наследует от Hashtable
, методы put
и putAll
может применяться к объекту Properties
. Их использование сильно обескуражены, поскольку они позволяют вызывающему абоненту вставлять записи, чьи ключи или значения не являются String
s. Вместо этого следует использовать метод setProperty
.
Чтобы поддерживать совместимость с этим, у дизайнеров не было другого выбора, кроме как сделать его наследуемым Map<Object, Object>
в Java 5. Это неудачный результат стремления к полной обратной совместимости, что делает новый код излишне запутанным.
Если вы используете только свойства строки в своем Properties
объекте, вы можете уйти с непроверенным списком в своем конструкторе:
Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);
или без каких-либо копий:
Map<String, String> map = (Map<String, String>) properties;
Ответ 10
это происходит только потому, что для конструктора HashMap требуется аргумент типа Generic Map и Properties реализует Map.
Это будет работать, хотя с предупреждением
Properties properties = new Properties();
Map<String, String> map = new HashMap(properties);
Ответ 11
Первое,
Класс свойств основан на Hashtable, а не в Hashmap. Класс свойств в основном расширяет Hashtable
В классе HashMap нет такого конструктора, который принимает объект свойств и возвращает вам объект hashmap. Так что вы делаете НЕ правильно. Вы должны иметь возможность передать объект свойств в хеш-таблицу.
Ответ 12
я использую это:
for (Map.Entry<Object, Object> entry:properties.entrySet()) {
map.put((String) entry.getKey(), (String) entry.getValue());
}