Map<String,Object>
をMap<String,String>
に変換するにはどうすればよいですか?
これは動作しません:
Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>(map);
Objects
にStrings
のみが含まれている場合は、次のようにできます。
_Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if(entry.getValue() instanceof String){
newMap.put(entry.getKey(), (String) entry.getValue());
}
}
_
すべてのObjects
がString
ではない場合、_(String) entry.getValue()
_をentry.getValue().toString()
に置き換えることができます。
Java 8/streamsができたので、リストにもう1つ考えられる答えを追加できます。
各値が実際にareString
オブジェクトであると仮定すると、String
へのキャストは安全であるはずです。それ以外の場合は、オブジェクトを文字列にマッピングする他のメカニズムを使用できます。
Map<String,Object> map = new HashMap<>();
Map<String,String> newMap = map.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));
ジェネリック型は、コンパイル時の抽象化です。実行時に、すべてのマップは同じタイプMap<Object, Object>
を持ちます。したがって、値が文字列であることを確信している場合は、Javaコンパイラーをチートできます:
Map<String, Object> m1 = new HashMap<String, Object>();
Map<String, String> m2 = (Map) m1;
あるコレクションから別のコレクションにキーと値をコピーすることは冗長です。しかし、このアプローチはジェネリック型の安全性に違反するため、依然として良くありません。そのようなことを避けるために、コードを再検討する必要があるかもしれません。
これを行うには2つの方法があります。 1つは非常に単純ですが、安全ではありません。
_Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> newMap = new HashMap<String, String>((Map)map); // unchecked warning
_
もう1つの方法はコンパイラの警告がなく、実行時の型の安全性を保証します。これはより堅牢です。 (結局、元のマップに文字列値のみが含まれることを保証することはできません。さもなければ、そもそも_Map<String, String>
_にならないのはなぜですか?)
_Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> newMap = new HashMap<String, String>();
@SuppressWarnings("unchecked") Map<String, Object> intermediate =
(Map)Collections.checkedMap(newMap, String.class, String.class);
intermediate.putAll(map);
_
不可能
これは少し直感に反します。
「Apple is-a fruit」に遭遇していますが、「Every Fruit is a Apple」ではありません
新しいマップを作成して、instance of with String
ObjectからStringにキャストしているときに、例外をキャッチして報告することをお勧めします(何らかの方法で、ここでメッセージを出力するだけです。これは一般に悪いことです)。
Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
try{
newMap.put(entry.getKey(), (String) entry.getValue());
}
catch(ClassCastException e){
System.out.println("ERROR: "+entry.getKey()+" -> "+entry.getValue()+
" not added, as "+entry.getValue()+" is not a String");
}
}
ブルートキャストと抑制された警告でこれを行うことができますが
Map<String,Object> map = new HashMap<String,Object>();
// Two casts in a row. Note no "new"!
@SuppressWarnings("unchecked")
Map<String,String> newMap = (HashMap<String,String>)(Map)map;
それは全体のポイントが本当に欠けています。 :)
狭いジェネリック型をより広いジェネリック型に変換しようとすると、そもそも間違った型を使用していることになります。
たとえば、大量のテキストを処理するプログラムがあるとします。 Objects
(!!)を使用して処理の前半を行い、次にString
として正しい型付けで後半を行うことを決定すると、Object
からString
へ。幸いなことに、これを行うことができますJava(この場合は簡単です)-しかし、前半で弱い型付けを使用しているという事実を隠しています。悪い習慣、引数はありません。
ここには違いはありません(キャストするのがより困難です)。常に厳密な型指定を使用する必要があります。少なくともいくつかのベースタイプを使用します。その後、ジェネリックワイルドカード(「?extends BaseType」または「?super BaseType」)を使用して、タイプの互換性と自動キャストを行うことができます。さらに良いのは、正しい既知のタイプを使用することです。あらゆるタイプで実際に使用できる100%の一般化コードがない限り、Objectを使用しないでください。
お役に立てば幸いです! :) :)
注:汎用の厳密な型指定と型キャストは.Javaコードにのみ存在します。 .classにコンパイルした後、一般的な型パラメーターとキーと値の自動型キャストのない生の型(MapとHashMap)が残ります。ただし、.Javaコード自体は厳密に型指定されており簡潔であるため、非常に役立ちます。
ここでの優れたソリューションは、null
値の処理を考慮したもう1つのオプションです。
Map<String,Object> map = new HashMap<>();
Map<String,String> stringifiedMap = map.entrySet().stream()
.filter(m -> m.getKey() != null && m.getValue() !=null)
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));
以下は、既存のエントリを変換します。
TransformedMap.decorateTransform(params, keyTransformer, valueTransformer)
どことして
MapUtils.transformedMap(Java.util.Map map, keyTransformer, valueTransformer)
新しいエントリのみをマップに変換します
Java 8方法で_Map<String, Object>
_を_Map<String, String>
_に変換します。このソリューションはnull
値を処理します。
_Map<String, String> keysValuesStrings = keysValues.entrySet().stream()
.filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().toString()));
_
private Map<String, String> convertAttributes(final Map<String, Object> attributes) {
final Map<String, String> result = new HashMap<String, String>();
for (final Map.Entry<String, Object> entry : attributes.entrySet()) {
result.put(entry.getKey(), String.valueOf(entry.getValue()));
}
return result;
}