Guava nous fournit d'excellentes méthodes d'usine pour les types Java, tels que Maps.newHashMap().
Mais existe-t-il aussi des constructeurs pour Java Maps?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
Guava nous fournit d'excellentes méthodes d'usine pour les types Java, tels que Maps.newHashMap().
Mais existe-t-il aussi des constructeurs pour Java Maps?
HashMap<String,Integer> m = Maps.BuildHashMap.
put("a",1).
put("b",2).
build();
Réponses:
Puisque l' Mapinterface Java 9 contient:
Map.of(k1,v1, k2,v2, ..) Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ..). Les limites de ces méthodes d'usine sont qu'elles:
null s comme clés et / ou valeurs (si vous avez besoin de stocker des valeurs nulles, jetez un œil à d'autres réponses)Si nous avons besoin d'une carte mutable (comme HashMap), nous pouvons utiliser son constructeur de copie et le laisser copier le contenu de la carte créée viaMap.of(..)
Map<Integer, String> map = new HashMap<>( Map.of(1,"a", 2,"b", 3,"c") );
nullvaleurs, ce qui peut poser problème selon le cas d'utilisation.
Map.of(k1,v1, k2,v2, ...)peut être utilisé en toute sécurité lorsque nous n'avons pas beaucoup de valeurs. Pour une plus grande quantité de valeurs Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)nous donne un code plus lisible qui est moins sujet aux erreurs (sauf si je vous ai mal compris).
Il n'y a rien de tel pour HashMaps, mais vous pouvez créer un ImmutableMap avec un générateur:
final Map<String, Integer> m = ImmutableMap.<String, Integer>builder().
put("a", 1).
put("b", 2).
build();
Et si vous avez besoin d'une carte mutable, vous pouvez simplement la transmettre au constructeur HashMap.
final Map<String, Integer> m = Maps.newHashMap(
ImmutableMap.<String, Integer>builder().
put("a", 1).
put("b", 2).
build());
ImmutableMapne prend pas en charge les nullvaleurs. Il y a donc une limitation de cette approche: vous ne pouvez pas définir de valeurs dans votre HashMapto null.
new HashMapconstructeur Java au lieu de la Maps.newHashMapméthode statique ?
Pas tout à fait un constructeur, mais utilisant un initialiseur:
Map<String, String> map = new HashMap<String, String>() {{
put("a", "1");
put("b", "2");
}};
map instanceof HashMapfaux? Cela semble être une idée pas terrible.
map.getClass()==HashMap.classrenverra false. Mais c'est un test stupide de toute façon. HashMap.class.isInstance(map)devrait être préféré, et cela retournera vrai.
C'est similaire à la réponse acceptée, mais un peu plus propre, à mon avis:
ImmutableMap.of("key1", val1, "key2", val2, "key3", val3);
Il existe plusieurs variantes de la méthode ci-dessus, et elles sont parfaites pour créer des cartes statiques, immuables et immuables.
En voici un très simple ...
public class FluentHashMap<K, V> extends java.util.HashMap<K, V> {
public FluentHashMap<K, V> with(K key, V value) {
put(key, value);
return this;
}
public static <K, V> FluentHashMap<K, V> map(K key, V value) {
return new FluentHashMap<K, V>().with(key, value);
}
}
puis
import static FluentHashMap.map;
HashMap<String, Integer> m = map("a", 1).with("b", 2);
Voir https://gist.github.com/culmat/a3bcc646fa4401641ac6eb01f3719065
Un simple constructeur de carte est simple à écrire:
public class Maps {
public static <Q,W> MapWrapper<Q,W> map(Q q, W w) {
return new MapWrapper<Q, W>(q, w);
}
public static final class MapWrapper<Q,W> {
private final HashMap<Q,W> map;
public MapWrapper(Q q, W w) {
map = new HashMap<Q, W>();
map.put(q, w);
}
public MapWrapper<Q,W> map(Q q, W w) {
map.put(q, w);
return this;
}
public Map<Q,W> getMap() {
return map;
}
}
public static void main(String[] args) {
Map<String, Integer> map = Maps.map("one", 1).map("two", 2).map("three", 3).getMap();
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
}
Vous pouvez utiliser:
HashMap<String,Integer> m = Maps.newHashMap(
ImmutableMap.of("a",1,"b",2)
);
Ce n'est pas aussi élégant et lisible, mais fait le travail.
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);, meilleur?
HashMapest mutable; il n'y a pas besoin de constructeur.
Map<String, Integer> map = Maps.newHashMap();
map.put("a", 1);
map.put("b", 2);
ImmutableSet. Si vous voulez vraiment qu'il soit modifiable, vous pouvez l'initialiser dans le constructeur ou un bloc d'initialisation d'instance ou un bloc d'initialisation statique s'il s'agit d'un champ statique.
ImmutableMapévidemment.
{{init();}}(pas dans le constructeur, car d'autres constructeurs pourraient l'oublier). Et c'est bien que ce soit une sorte d'action atomique. Si la carte est volatile, l'initialiser avec un constructeur garantit qu'elle est toujours soit nullou dans l'état final, jamais à moitié remplie.
Vous pouvez utiliser l'API fluent dans les collections Eclipse :
Map<String, Integer> map = Maps.mutable.<String, Integer>empty()
.withKeyValue("a", 1)
.withKeyValue("b", 2);
Assert.assertEquals(Maps.mutable.with("a", 1, "b", 2), map);
Voici un blog avec plus de détails et d'exemples.
Remarque: je suis un committer pour les collections Eclipse.
J'avais une exigence similaire il y a quelque temps. Cela n'a rien à voir avec la goyave mais vous pouvez faire quelque chose comme ça pour être en mesure de construire proprement unMap utilisant un constructeur couramment.
Créez une classe de base qui étend Map.
public class FluentHashMap<K, V> extends LinkedHashMap<K, V> {
private static final long serialVersionUID = 4857340227048063855L;
public FluentHashMap() {}
public FluentHashMap<K, V> delete(Object key) {
this.remove(key);
return this;
}
}
Ensuite, créez le constructeur fluide avec des méthodes adaptées à vos besoins:
public class ValueMap extends FluentHashMap<String, Object> {
private static final long serialVersionUID = 1L;
public ValueMap() {}
public ValueMap withValue(String key, String val) {
super.put(key, val);
return this;
}
... Add withXYZ to suit...
}
Vous pouvez ensuite l'implémenter comme ceci:
ValueMap map = new ValueMap()
.withValue("key 1", "value 1")
.withValue("key 2", "value 2")
.withValue("key 3", "value 3")
C'est quelque chose que j'ai toujours voulu, en particulier lors de la configuration des montages de test. Enfin, j'ai décidé d'écrire un constructeur simple et fluide qui pourrait créer n'importe quelle implémentation de Map - https://gist.github.com/samshu/b471f5a2925fa9d9b718795d8bbdfe42#file-mapbuilder-java
/**
* @param mapClass Any {@link Map} implementation type. e.g., HashMap.class
*/
public static <K, V> MapBuilder<K, V> builder(@SuppressWarnings("rawtypes") Class<? extends Map> mapClass)
throws InstantiationException,
IllegalAccessException {
return new MapBuilder<K, V>(mapClass);
}
public MapBuilder<K, V> put(K key, V value) {
map.put(key, value);
return this;
}
public Map<K, V> build() {
return map;
}
En voici un que j'ai écrit
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class MapBuilder<K, V> {
private final Map<K, V> map;
/**
* Create a HashMap builder
*/
public MapBuilder() {
map = new HashMap<>();
}
/**
* Create a HashMap builder
* @param initialCapacity
*/
public MapBuilder(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
/**
* Create a Map builder
* @param mapFactory
*/
public MapBuilder(Supplier<Map<K, V>> mapFactory) {
map = mapFactory.get();
}
public MapBuilder<K, V> put(K key, V value) {
map.put(key, value);
return this;
}
public Map<K, V> build() {
return map;
}
/**
* Returns an unmodifiable Map. Strictly speaking, the Map is not immutable because any code with a reference to
* the builder could mutate it.
*
* @return
*/
public Map<K, V> buildUnmodifiable() {
return Collections.unmodifiableMap(map);
}
}
Vous l'utilisez comme ceci:
Map<String, Object> map = new MapBuilder<String, Object>(LinkedHashMap::new)
.put("event_type", newEvent.getType())
.put("app_package_name", newEvent.getPackageName())
.put("activity", newEvent.getActivity())
.build();
En utilisant java 8:
C'est une approche de Java-9 Map.ofEntries(Map.entry(k1,v1), Map.entry(k2,v2), ...)
public class MapUtil {
import static java.util.stream.Collectors.toMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;
private MapUtil() {}
@SafeVarargs
public static Map<String, Object> ofEntries(SimpleEntry<String, Object>... values) {
return Stream.of(values).collect(toMap(Entry::getKey, Entry::getValue));
}
public static SimpleEntry<String, Object> entry(String key, Object value) {
return new SimpleEntry<String, Object>(key, value);
}
}
Comment utiliser:
import static your.package.name.MapUtil.*;
import java.util.Map;
Map<String, Object> map = ofEntries(
entry("id", 1),
entry("description", "xyz"),
entry("value", 1.05),
entry("enable", true)
);
Underscore-java peut construire hashmap.
Map<String, Object> value = U.objectBuilder()
.add("firstName", "John")
.add("lastName", "Smith")
.add("age", 25)
.add("address", U.arrayBuilder()
.add(U.objectBuilder()
.add("streetAddress", "21 2nd Street")
.add("city", "New York")
.add("state", "NY")
.add("postalCode", "10021")))
.add("phoneNumber", U.arrayBuilder()
.add(U.objectBuilder()
.add("type", "home")
.add("number", "212 555-1234"))
.add(U.objectBuilder()
.add("type", "fax")
.add("number", "646 555-4567")))
.build();
// {firstName=John, lastName=Smith, age=25, address=[{streetAddress=21 2nd Street,
// city=New York, state=NY, postalCode=10021}], phoneNumber=[{type=home, number=212 555-1234},
// {type=fax, number=646 555-4567}]}