Conversione di java.util.Properties in HashMap <String, String>


Risposte:


86

Questo perché si PropertiesestendeHashtable<Object, Object> (che, a sua volta, implementa Map<Object, Object>). Tenti di inserirlo in un file Map<String, String>. È quindi incompatibile.

Devi inserire le proprietà della stringa una per una nella tua mappa ...

Per esempio:

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

1
Sì, ma non è questo il problema qui: gli argomenti generici non corrispondono. Puoi alimentare quello che vuoi in a Hashtable<Object, Object>, anche cose che non sono stringhe - anche chiavi che non sono stringhe.
fge

@assylias: No, neanche questo verrà compilato.
Jon Skeet

13
in 1,8 puoi fare properties.forEach ((k, v) -> map.put ((String) k, (String) v));
ModdyFire

1
Oppure, se non hai già la mappa in mano properties.entrySet (). Stream (). Collect (Collectors.toMap (e -> (String) e.getKey (), e -> (String) e.getValue ( )))
Tonsic

46

Il modo efficiente per farlo è semplicemente eseguire il cast su una mappa generica come segue:

Properties props = new Properties();

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

Questo convertirà un Map<Object, Object>in una mappa grezza, che è "ok" per il compilatore (solo avvertimento). Una volta che avremo un raw Map, verrà Map<String, String>eseguito il cast al quale sarà anche "ok" (un altro avvertimento). Puoi ignorarli con l'annotazione@SuppressWarnings({ "unchecked", "rawtypes" })

Questo funzionerà perché nella JVM l'oggetto non ha realmente un tipo generico. I tipi generici sono solo un trucco che verifica le cose in fase di compilazione.

Se una chiave o un valore non è una stringa, verrà ClassCastExceptiongenerato un errore. Con l' Propertiesimplementazione corrente è molto improbabile che ciò accada, a condizione che non si utilizzino i metodi di chiamata mutabili del super Hashtable<Object,Object>di Properties.

Quindi, se non fai cose brutte con la tua istanza Properties, questa è la strada da percorrere.


La domanda è convertire in HashMap. Nessuna mappa.
AlikElzin-kilaka

3
Sì, il titolo della domanda lo dice, ma l'obiettivo è di avere Mapun'istanza almeno al codice dato, quindi ho pensato che questo è ciò di cui ha bisogno
padilo

Anche se mi piacciono le altre soluzioni puriste, questa soluzione mi torna utile poiché è solo una semplice linea.
Alfonso Nishikawa,


27

Cosa ne pensi di questo?

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

Provocherà un avviso, ma funziona senza iterazioni.


4
@ fge: non è un Map<Object, Object>, è un Mapargomento (tipo grezzo). Questa risposta è corretta
Lukas Eder il

2
Eh, sì, ho provato con Eclipse. Ancora una di quelle differenze generiche tra Eclipse e javac? .... no, funziona anche con javac
Lukas Eder il

4
Funziona ma l'iterazione avviene ancora. Se guardi il codice sorgente per HashMap, il costruttore fondamentalmente itera attraverso il parametro generico della mappa. Quindi il tempo di calcolo non cambia ma il codice è sicuramente più conciso.
Simeon G

Come affermato nella risposta precedente, non è necessario creare una nuova istanza e iterare sull'oggetto proprietà. Usa solo una sequenza di calchi: (Map<String, String>) ((Map) properties)
Ricardo Veloso

22

Il modo in cui Java 8:

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

C'è un modo per utilizzare il riferimento al metodo invece di lambda. Problemi relativi al qube del sonar.
Viyaan Jhiingade

16

Propertiesattrezzi Map<Object, Object>- non Map<String, String>.

Stai provando a chiamare questo costruttore:

public HashMap(Map<? extends K,? extends V> m)

... con Ked Ventrambi come String.

Ma Map<Object, Object>non è un Map<? extends String, ? extends String>... può contenere chiavi e valori non stringa.

Questo funzionerebbe:

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

... ma non ti sarebbe così utile.

Fondamentalmente, Propertiesnon avrebbe mai dovuto essere una sottoclasse di HashTable... questo è il problema. Dalla v1, è sempre stato in grado di memorizzare chiavi e valori non String, nonostante ciò fosse contro l'intenzione. Se invece fosse stata utilizzata la composizione, l'API avrebbe potuto funzionare solo con chiavi / valori stringa e tutto sarebbe andato bene.

Potresti volere qualcosa del genere:

Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
    map.put(key, properties.getProperty(key));
}

apparentemente non è nemmeno possibile farlo esplicitamente Properties<String,String> properties = new Properties<String,String>();. Peculiare.
eis

1
@eis Questo è di progettazione, di per Propertiessé non è generico.
Mattias Buelens

Preferisco dire che è da una serie sfortunata di scelte piuttosto che dal design, ma sì.
eis

2
@eis: No, è in base alla progettazione che Proprietà deve essere una mappa da stringa a stringa. Ha senso che non sia generico. Non ha senso aggiungere chiavi / valori non di stringa.
Jon Skeet


8

Se sai che il tuo Propertiesoggetto contiene solo <String, String>voci, puoi ricorrere a un tipo grezzo:

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

4

Il problema è che Propertiesimplementa Map<Object, Object>, mentre il HashMapcostruttore si aspetta un file Map<? extends String, ? extends String>.

Questa risposta spiega questa decisione (abbastanza contro-intuitiva). In breve: prima di Java 5, Propertiesimplementato Map(poiché non c'erano generici allora). Ciò significava che potevi mettere qualsiasi cosa Object in un Propertiesoggetto. Questo è ancora nella documenazione:

Poiché Propertieseredita da Hashtable, i metodi pute putAllpossono essere applicati a un Propertiesoggetto. Il loro uso è fortemente sconsigliato in quanto consentono al chiamante di inserire voci le cui chiavi o valori non sono Strings. IlsetProperty metodo dovrebbe essere utilizzato invece.

Per mantenere la compatibilità con questo, i progettisti non hanno avuto altra scelta che farlo ereditare Map<Object, Object> in Java 5. È uno sfortunato risultato della ricerca della piena compatibilità all'indietro che rende il nuovo codice inutilmente contorto.

Se usi solo le proprietà della stringa nel tuo Propertiesoggetto, dovresti essere in grado di farla franca con un cast non controllato nel tuo costruttore:

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

o senza alcuna copia:

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

Questa è la firma del costruttore HashMap public HashMap(Map<? extends K, ? extends V> m). Non si aspetta unMap<String, String>
Mubin

@Mubin Va bene, ho semplificato un po 'la questione. Tuttavia, l'argomento vale: a Map<Object, Object>non può essere utilizzato per un argomento formale di tipo` Map <? estende String,? estende String> `.
Mattias Buelens

2

questo è solo perché il costruttore di HashMap richiede un argomento di tipo generico Map e Properties implementa Map.

Funzionerà, anche se con un avvertimento

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

1

Puoi usare questo:

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

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

0

Prima cosa,

La classe delle proprietà è basata su Hashtable e non su Hashmap. La classe Properties fondamentalmente estende Hashtable

Non esiste un tale costruttore nella classe HashMap che prenda un oggetto proprietà e ti restituisca un oggetto hashmap. Quindi quello che stai facendo NON è corretto. Dovresti essere in grado di eseguire il cast dell'oggetto delle proprietà in riferimento alla tabella hash.


0

io uso questo:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.