Convertir la carte <String, Object> en carte <String, String>
Comment puis-je convertir Map<String,Object>
en Map<String,String>
?
Cela ne fonctionne pas:
Map<String,Object> map = new HashMap<String,Object>(); //Object is containing String
Map<String,String> newMap =new HashMap<String,String>(map);
Si votre Objects
ne contient que Strings
, alors vous pouvez le faire comme ceci:
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());
}
}
Si chaque Objects
n'est pas String
, vous pouvez remplacer (String) entry.getValue()
dans entry.getValue().toString()
.
Maintenant que nous avons Java 8/streams, nous pouvons ajouter une autre réponse possible à la liste:
En supposant que chacune des valeurs sont String
objets, la conversion en String
devrait être sécurisée. Sinon, un autre mécanisme permettant de mapper les objets aux chaînes peut être utilisé.
Map<String,Object> map = new HashMap<>();
Map<String,String> newMap = map.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue()));
Les types génériques sont une abstraction de temps de compilation. Au moment de l'exécution, toutes les cartes auront le même type Map<Object, Object>
. Donc, si vous êtes sûr que les valeurs sont des chaînes, vous pouvez tricher avec le compilateur Java:
Map<String, Object> m1 = new HashMap<String, Object>();
Map<String, String> m2 = (Map) m1;
La copie de clés et de valeurs d'une collection à une autre est redondante. Mais cette approche n’est toujours pas bonne, car elle viole la sécurité du type générique. Peut-être devriez-vous reconsidérer votre code pour éviter de telles choses.
Il y a deux façons de faire ça. L'un est très simple mais dangereux:
Map<String, Object> map = new HashMap<String, Object>();
Map<String, String> newMap = new HashMap<String, String>((Map)map); // unchecked warning
L’autre moyen ne comporte aucun avertissement du compilateur et garantit la sécurité des types au moment de l’exécution, ce qui est plus robuste. (Après tout, vous ne pouvez pas garantir que la carte d'origine ne contient que des valeurs de chaîne, sinon pourquoi ne s'agirait-il pas de 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);
Pas possible.
C'est un peu contre-intuitif.
Vous rencontrez la "pomme est un fruit" mais "chaque fruit n'est pas une pomme"
Allez créer une nouvelle carte et vérifier avec instance of with String
Pendant que vous passez d'objet en chaîne, je vous recommande de capturer et de signaler (d'une certaine manière, je viens ici d'imprimer un message, qui est généralement mauvais) l'exception.
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");
}
}
Alors que vous pouvez le faire avec le casting brutal et les avertissements supprimés
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;
cela manque vraiment le point entier. :)
Une tentative de conversion d'un type générique étroit en un type générique plus large signifie que vous utilisez un type incorrect en premier lieu.
Par analogie: imaginez que vous avez un programme qui effectue un traitement de texte volumineux. Imaginez que vous effectuez la première moitié du traitement en utilisant Objects
(!!), puis que vous décidiez de faire la seconde moitié avec une saisie correcte en tant que String
, de sorte que vous réduisez de Object
à String
. Heureusement, vous pouvez le faire en Java (facilement dans ce cas), mais cela masque simplement le fait que vous utilisez une frappe faible en première moitié. Mauvaise pratique, pas de discussion.
Aucune différence ici (juste plus difficile à lancer). Vous devez toujours utiliser une frappe forte. Au minimum, utilisez un type de base - vous pouvez utiliser des caractères génériques ("? Extend BaseType" ou "? Super BaseType") pour assurer la compatibilité des types et la conversion automatique. Encore mieux, utilisez le type connu correct. N'utilisez jamais Object sauf si vous avez un code 100% généralisé pouvant être utilisé avec n'importe quel type.
J'espère que cela pourra aider! :) :)
Remarque: Le typage fort générique et la transposition de types n'existent que dans le code .Java. Après la compilation dans .class, il ne reste que des types bruts (Map et HashMap) sans paramètres de type génériques, plus la transposition automatique des clés et des valeurs. Mais cela aide beaucoup car le code .Java lui-même est fortement typé et concis.
Excellentes solutions ici, juste une option supplémentaire prenant en compte le traitement des valeurs null
:
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()));
Ce qui suit va transformer vos entrées existantes.
TransformedMap.decorateTransform(params, keyTransformer, valueTransformer)
Tandis que
MapUtils.transformedMap(Java.util.Map map, keyTransformer, valueTransformer)
ne transforme que de nouvelles entrées dans votre carte
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;
}