Перетворення java.util.Properties в HashMap <String, String>


Відповіді:


86

Це тому, що PropertiesрозширюєHashtable<Object, Object> (що, в свою чергу, реалізує Map<Object, Object>). Ви намагаєтесь передати це в a Map<String, String>. Тому він несумісний.

Вам потрібно подавати властивості рядка по черзі на вашу карту ...

Наприклад:

for (final String name: properties.stringPropertyNames())
    map.put(name, properties.getProperty(name));

1
Так, але це не проблема тут: загальні аргументи не збігаються. Ви можете годувати все, що завгодно Hashtable<Object, Object>, навіть речі, які не є рядками - навіть ключі, які не є рядками.
fge

@assylias: Ні, це теж не компілюється.
Джон Скіт,

12
в 1,8 ви можете зробити Properties.forEach ((k, v) -> map.put ((String) k, (String) v));
ModdyFire

1
Або якщо у вас ще немає карти в руках properties.entrySet (). Stream (). Collect (Collectors.toMap (e -> (String) e.getKey (), e -> (String) e.getValue ( )))
Тонсіч

46

Ефективний спосіб зробити це - просто перейти на загальну карту наступним чином:

Properties props = new Properties();

Map<String, String> map = (Map)props;

Це перетворить a Map<Object, Object>на вихідну карту, що є "нормально" для компілятора (лише попередження). Після того, як ми отримаємо сировину, Mapвона буде передана, і Map<String, String>вона також буде "добре" (ще одне попередження). Ви можете ігнорувати їх за допомогою анотації@SuppressWarnings({ "unchecked", "rawtypes" })

Це буде працювати, оскільки в JVM об'єкт насправді не має загального типу. Загальні типи - це лише фокус, який перевіряє речі під час компіляції.

Якщо якийсь ключ або значення не є рядком, це призведе до ClassCastExceptionпомилки. При поточній Propertiesреалізації це дуже малоймовірно , щоб це сталося, до тих пір , поки ви не використовувати методи змінювані викликів з супер Hashtable<Object,Object>частини Properties.

Отже, якщо ви не робите неприємних дій із вашим екземпляром Properties, це шлях.


Питання полягає в перетворенні на HashMap. Не будь-яка карта.
AlikElzin-kilaka

3
Так, заголовок запитання говорить про це, але мета полягає в тому, щоб мати Mapпримірник принаймні за даним кодом, тому я подумав, що це те, що йому потрібно
padilo

Хоча мені подобаються інші рішення пуристів, це рішення мені дуже зручно, оскільки це лише одна проста лінія.
Альфонсо Нісікава,


27

Як щодо цього?

   Map properties = new Properties();
   Map<String, String> map = new HashMap<String, String>(properties);

Викликає попередження, але працює без ітерацій.


4
@fge: Це не а Map<Object, Object>, це Mapаргумент (необроблений тип). Ця відповідь правильна
Лукас Едер

2
Так, так, я спробував з Eclipse. Одна з тих загальних відмінностей між Eclipse та javac знову? .... ні, працює і з javac
Лукас Едер

4
Це працює, але ітерація все одно трапляється. Якщо поглянути на вихідний код HashMap, конструктор в основному перебирає загальний параметр map. Тож час обчислення не змінюється, але код, звичайно, є більш стислим.
Симеон Г

Як зазначалося в попередній відповіді, немає необхідності створювати новий екземпляр та перебирати об'єкт властивостей. Просто використовуйте послідовність кастів: (Map<String, String>) ((Map) properties)
Рікардо Велосо

22

Java 8 спосіб:

properties.entrySet().stream().collect(
    Collectors.toMap(
         e -> e.getKey().toString(),
         e -> e.getValue().toString()
    )
);

Чи є спосіб використовувати посилання на метод замість лямбда. З-за проблем сонарних кве.
Viyaan Jhiingade

16

Propertiesзнаряддя Map<Object, Object>- ні 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));
}

очевидно, це також неможливо зробити явно Properties<String,String> properties = new Properties<String,String>();. Своєрідний.
eis

1
@eis Це за задумом, Propertiesсаме по собі не є загальним.
Маттіас Буеленс,

Я б скоріше сказав, що це невдалий вибір варіантів, а не дизайн, але так.
eis

2
@eis: Ні, саме за власним задумом властивість має бути картою між рядками. Має сенс, що він не є загальним. Це НЕ має сенсу , що ви можете додати нестроковие ключів / значень.
Джон Скіт,


8

Якщо ви знаєте, що ваш Propertiesоб’єкт містить лише <String, String>записи, ви можете вдатися до необробленого типу:

Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);

4

Проблема в тому, що Propertiesреалізує Map<Object, Object>, тоді як HashMapконструктор очікує a Map<? extends String, ? extends String>.

Ця відповідь пояснює це (досить протиінтуїтивне) рішення. Коротше кажучи: до Java 5 Propertiesвпроваджено Map(оскільки тоді ще не було дженериків). Це означало, що ви можете покласти будь- Object який Propertiesпредмет. Це все ще в документі:

Оскільки Propertiesспадщини від Hashtable, методи putand putAllможуть бути застосовані до Propertiesоб'єкта. Їх використання настійно не рекомендується, оскільки вони дозволяють абоненту вставляти записи, ключі або значення яких не є Strings. Натомість 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;

Це підпис конструктора HashMap public HashMap(Map<? extends K, ? extends V> m). Це не очікуєMap<String, String>
Мубін

@Mubin Гаразд, я трохи спростив справу. І все-таки аргумент справедливий: a Map<Object, Object>не можна використовувати для офіційного аргументу типу` Map <? розширює рядок,? розширює String> `.
Маттіас Буеленс,

2

це лише тому, що конструктор HashMap вимагає аргументу загального типу Map, а Properties реалізує Map.

Це спрацює, хоча з попередженням

    Properties properties = new Properties();
    Map<String, String> map = new HashMap(properties);

1

Ви можете використовувати це:

Map<String, String> map = new HashMap<>();

props.forEach((key, value) -> map.put(key.toString(), value.toString()));

0

Перша річ,

Клас властивостей базується на Hashtable, а не на Hashmap. Клас властивостей в основному розширює Hashtable

Немає такого конструктора в класі HashMap, який бере об'єкт властивостей і повертає вам об'єкт hashmap. Тож те, що ви робите, НЕ правильне. Ви повинні мати можливість передати об’єкт властивостей у хеш-табличне посилання.


0

я використовую це:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.