java.util.PropertiesをHashMap <String、String>に変換する


回答:


86

これは、PropertiesextendsHashtable<Object, Object>(これが実装するMap<Object, Object>)のためです。あなたはそれをに送り込もうとしますMap<String, String>。したがって、互換性はありません。

文字列のプロパティを1つずつマップにフィードする必要があります...

例えば:

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

1
はい、しかしそれはここでは問題ではありません:一般的な引数が一致しません。Hashtable<Object, Object>文字列ではないものでも、文字列ではないキーでも、好きなものをフィードできます。
fge 2013年

@assylias:いいえ、それもコンパイルされません。
Jon Skeet

12
1,8では、properties.forEach((k、v)-> map.put((String)k、(String)v));を実行できます。
moddyFire 2017

1
または、まだマップが手元にない場合は、properties.entrySet()。stream()。collect(Collectors.toMap(e->(String)e.getKey()、e->(String)e.getValue( )))
Tonsic 2018年

46

これを行う効率的な方法は、次のように一般的なマップにキャストすることです。

Properties props = new Properties();

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

これMap<Object, Object>により、が生のマップに変換されます。これは、コンパイラにとって「問題ありません」(警告のみ)。生を取得Mapすると、キャストさMap<String, String>れ、「OK」になります(別の警告)。注釈付きで無視できます@SuppressWarnings({ "unchecked", "rawtypes" })

JVMでは、オブジェクトは実際にはジェネリック型を持たないため、これは機能します。ジェネリック型は、コンパイル時に物事を検証するための単なるトリックです。

一部のキーまたは値が文字列でない場合、ClassCastExceptionエラーが発生します。現在ではProperties実装これは、限り、あなたはスーパーから変更可能なコール・メソッドを使用していないとして、起こることは非常にそうであるHashtable<Object,Object>Properties

したがって、Propertiesインスタンスで厄介なことをしない場合は、これが最適な方法です。


問題は、HashMapに変換することです。マップはありません。
AlikElzin-kilaka 2017年

3
はい、質問のタイトルにはそう書かれていMapますが、目標は少なくとも指定されたコードにインスタンスを作成することなので、これが彼に必要なものだと思いました
padilo 2017年

私は他の純粋主義者の解決策が好きですが、この解決策は1つの単純な行しかないので、私には便利です。
アルフォンソ西川


27

これはどう?

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

警告が発生しますが、繰り返しなしで機能します。


4
@fge:それはMap<Object, Object>Map引数ではなく、引数(生の型)です。この答えは正しいです
Lukas Eder

2
ええ、はい、私はEclipseで試しました。Eclipseとjavacの一般的な違いの1つは?....いいえ、javacでも動作します
Lukas Eder

4
これは機能しますが、反復は引き続き発生します。HashMapのソースコードを見ると、コンストラクターは基本的に汎用マップパラメーターを反復処理します。したがって、計算時間は変わりませんが、コードは確かにより簡潔です。
シメオンG

前の回答で述べたように、新しいインスタンスを作成してプロパティオブジェクトを反復処理する必要はありません。ただ、キャストのシーケンスを使用: (Map<String, String>) ((Map) properties)
リカルド・ヴェローゾ

22

Java 8の方法:

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

ラムダの代わりにメソッド参照を使用する方法はありますか?ソナークベ問題のCos。
ViyaanJhiingade19年

16

Properties実装Map<Object, Object>-ではありませんMap<String, String>

このコンストラクターを呼び出そうとしています:

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

...とKV両方として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は仕様によるものであり、それ自体は一般的ではありません。
Mattias Buelens 2013年

設計ではなく、不幸な一連の選択によるものだと言いたいのですが、そうです。
eis

2
@eis:いいえ、プロパティが文字列から文字列へのマップであることを意図しているのは設計によるものです。それがジェネリックではないことは理にかなっています。それはしませんあなたは文字列以外のキー/値を追加できることを意味をなします。
Jon Skeet


8

もし、あんたが Propertiesオブジェクトに<String, String>エントリのみが含まれいるわかっている、raw型を使用できます。

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

4

問題は、をProperties実装することですがMap<Object, Object>HashMapコンストラクターがを期待しているのすることMap<? extends String, ? extends String>です。

この答えは、この(非常に直感に反する)決定を説明しています。つまり、Java 5より前にProperties実装されていましたMap(当時はジェネリックがなかったため)。これは、オブジェクトに任意のもの Objectを入れることができることを意味しましたPropertiesこれはまだ文書化されています:

からProperties継承するためHashtableputandputAllメソッドを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 2013年

@Mubinわかりました、私は問題を少し単純化しすぎました。それでも、引数は成り立ちます:aMap<Object, Object>はタイプ `Map <?の正式な引数には使用できません。文字列を拡張しますか?String> `を拡張します。
Mattias Buelens 2013年

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

初めにすること、

プロパティクラスは、HashmapではなくHashtableに基づいています。プロパティクラスは基本的にHashtableを拡張します

HashMapクラスには、プロパティオブジェクトを受け取り、ハッシュマップオブジェクトを返すようなコンストラクターはありません。だからあなたがしていることは正しくありません。プロパティのオブジェクトをハッシュテーブル参照にキャストできるはずです。


0

私はこれを使用します:

for (Map.Entry<Object, Object> entry:properties.entrySet()) {
    map.put((String) entry.getKey(), (String) entry.getValue());
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.