Comment puis-je initialiser une carte statique?

Comment initialiseriez-vous un Map statique en Java?

Première méthode: initialiseur statique
Méthode deux: initialiseur d'instance (sous-classe anonyme) ou une autre méthode?

Quels sont les avantages et les inconvénients de chacun?

Voici un exemple illustrant les deux méthodes:

import java.util.HashMap;
import java.util.Map;

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<Integer, String>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}
954
demandé sur Gerold Broser 2009-02-03 18:41:33

30 réponses

L'initialiseur d'instance est juste du sucre syntaxique dans ce cas, non? Je ne vois pas pourquoi vous avez besoin d'une classe anonyme supplémentaire juste pour initialiser. Et cela ne fonctionnera pas si la classe en cours de création est finale.

Vous pouvez également créer une carte immuable en utilisant un initialiseur statique:

public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}
962
répondu Miserable Variable 2015-02-25 16:06:25

J'aime la façon Goyave d'initialiser une carte statique et immuable:

static final Map<Integer, String> MY_MAP = ImmutableMap.of(
    1, "one",
    2, "two"
);

Comme vous pouvez le voir, il est très concis (en raison de la pratique usine méthodes dans ImmutableMap).

Si vous voulez la carte à plus de 5 entrées, vous ne pouvez plus utiliser ImmutableMap.of(). Au lieu de cela, essayez ImmutableMap.builder() le long de ces lignes:

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
    .put(1, "one")
    .put(2, "two")
    // ... 
    .put(15, "fifteen")
    .build();

Pour en savoir plus sur les avantages des utilitaires de collection immuables De Goyave, consultez Collections immuables expliquées dans L'utilisateur Goyave Guide de.

(Un sous-ensemble de) Goyave utilisé pour être appelé Google Collections. Si vous n'utilisez pas encore cette bibliothèque dans votre projet Java, jerecommande fortement de l'essayer! Goyave est rapidement devenu l'un des libs 3rd party gratuits les plus populaires et utiles pour Java, comme fellow SO users agree. (Si vous êtes nouveau, il y a d'excellentes ressources d'apprentissage derrière ce lien.)


Mise à Jour (2015): Comme pour Java 8, eh bien, je utiliserait toujours l'approche de la goyave car elle est beaucoup plus propre que toute autre chose. Si vous ne voulez pas de dépendance à la goyave, considérez une ancienne méthode d'initialisation simple. Le hack avec tableau bidimensionnel et API de flux est assez moche si vous me demandez, et devient plus moche si vous avez besoin de créer une carte dont les clés et les valeurs ne sont pas du même type (comme Map<Integer, String> dans la question).

Quant à l'avenir de la goyave en général, en ce qui concerne Java 8, Louis Wasserman a dit ceci en 2014, et [mise à jour] en 2016, il a été annoncé que Goyave 21 et correctement en charge Java 8.


Mise à jour (2016) : Comme le souligne Tagir Valeev, Java 9 va enfin rendre cela propre à faire en n'utilisant que du JDK pur, en ajoutant méthodes d'usine de commodité pour les collections:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);
379
répondu Jonik 2017-05-23 12:10:45

Je voudrais utiliser:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<Integer, String>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  1. il évite la classe anonyme, que je considère personnellement comme un mauvais style, et évite
  2. cela rend la création de la carte plus explicite
  3. cela rend la carte non modifiable
  4. comme MY_MAP est constant, je le nommerais comme constant
162
répondu Peter Štibraný 2009-02-03 21:40:14

Java 5 fournit cette syntaxe plus compacte:

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};
158
répondu Chris Noe 2009-07-15 21:29:54

Un avantage de la deuxième méthode est que vous pouvez l'envelopper avec Collections.unmodifiableMap() pour garantir que rien ne mettra à jour la collection plus tard:

private static final Map<Integer, String> CONSTANT_MAP = 
    Collections.unmodifiableMap(new HashMap<Integer, String>() {{ 
        put(1, "one");
        put(2, "two");
    }});

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!
81
répondu Outlaw Programmer 2018-07-18 06:02:08

Voici un initialiseur de carte statique Java 8 à une ligne:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =
    Arrays.stream(new String[][] {
        { "txt", "text/plain" }, 
        { "html", "text/html" }, 
        { "js", "application/javascript" },
        { "css", "text/css" },
        { "xml", "application/xml" },
        { "png", "image/png" }, 
        { "gif", "image/gif" }, 
        { "jpg", "image/jpeg" },
        { "jpeg", "image/jpeg" }, 
        { "svg", "image/svg+xml" },
    }).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

Edit: pour initialiser un Map<Integer, String>, comme dans la question, vous auriez besoin de quelque chose comme ceci:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
        {1, "one"},
        {2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

Edit (2): Il existe une meilleure version de type mixte par i_am_zero qui utilise un flux d'appels new SimpleEntry<>(k, v). Découvrez cette réponse: https://stackoverflow.com/a/37384773/3950982

55
répondu Luke Hutchison 2018-07-05 23:25:30

Dans Java 9:

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

Voir JEP 269 pour plus de détails. JDK 9 atteint disponibilité générale en septembre 2017.

43
répondu Tagir Valeev 2017-10-24 23:11:21

Avec Eclipse Collections (anciennement GS Collections), tous les éléments de travail:

import java.util.Map;

import org.eclipse.collections.api.map.ImmutableMap;
import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;

public class StaticMapsTest
{
    private static final Map<Integer, String> MAP =
        Maps.mutable.with(1, "one", 2, "two");

    private static final MutableMap<Integer, String> MUTABLE_MAP =
       Maps.mutable.with(1, "one", 2, "two");


    private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();


    private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =
        Maps.mutable.with(1, "one", 2, "two").asSynchronized();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =
        Maps.mutable.with(1, "one", 2, "two").toImmutable();


    private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =
        Maps.immutable.with(1, "one", 2, "two");
}

Vous pouvez également initialiser statiquement des cartes primitives avec des Collections Eclipse.

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;

public class StaticPrimitiveMapsTest
{
    private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two");

    private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asUnmodifiable();

    private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .asSynchronized();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =
            IntObjectMaps.mutable.<String>empty()
                    .withKeyValue(1, "one")
                    .withKeyValue(2, "two")
                    .toImmutable();

    private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =
            IntObjectMaps.immutable.<String>empty()
                    .newWithKeyValue(1, "one")
                    .newWithKeyValue(2, "two");
} 

Remarque: je suis un committer pour Eclipse Collections

27
répondu Donald Raab 2017-02-13 18:47:53

Je ne créerais jamais une sous-classe anonyme dans cette situation. Les initialiseurs statiques fonctionnent aussi bien, si vous souhaitez rendre la carte non modifiable par exemple:

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}
24
répondu eljenso 2009-02-04 08:19:39

Il y a une réponse proposée par Luke qui initialise une carte en utilisant Java 8 mais à mon humble avis, elle a l'air moche et difficile à lire. Nous pouvons créer un flux d'entrées de carte. Nous avons déjà deux implémentations de Entry dans java.util.AbstractMap sont SimpleEntry et SimpleImmutableEntry. Pour cet exemple, nous pouvons utiliser l'ancien comme:

import java.util.AbstractMap.*;
private static final Map<Integer, String> myMap = Stream.of(
            new SimpleEntry<>(1, "one"),
            new SimpleEntry<>(2, "two"),
            new SimpleEntry<>(3, "three"),
            new SimpleEntry<>(4, "four"),
            new SimpleEntry<>(5, "five"),
            new SimpleEntry<>(6, "six"),
            new SimpleEntry<>(7, "seven"),
            new SimpleEntry<>(8, "eight"),
            new SimpleEntry<>(9, "nine"),
            new SimpleEntry<>(10, "ten"))
            .collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));

Pour Java 9, nous pouvons également utiliser {[3] } comme suggéré par Tagir dans sa réponse ici .

16
répondu i_am_zero 2017-05-23 11:47:32

Peut-être qu'il est intéressant de consulter Google Collections , par exemple les vidéos qu'ils ont sur leur page. Ils fournissent diverses façons d'initialiser des cartes et des ensembles, et fournissent également des collections immuables.

Mise à Jour: Cette bibliothèque est nommé Goyave.

14
répondu Kaarel 2014-01-29 20:27:52

J'aime la classe anonyme, car il est facile de la gérer:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});
14
répondu Shushant 2016-04-28 06:12:40
public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

Si nous déclarons plus d'une constante alors ce code sera écrit en bloc statique et c'est difficile à maintenir à l'avenir. Il est donc préférable d'utiliser la classe anonyme.

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

Et il est suggéré d'utiliser unmodifiableMap pour les constantes autrement, il ne peut pas être traité comme constant.

9
répondu Leninkumar Koppoju 2010-06-03 08:30:03

Je pourrais fortement suggérer le style "Double brace initialization" sur le style de bloc statique.

Quelqu'un peut commenter qu'il n'aime pas la classe anonyme, les frais généraux, les performances, etc.

Mais que je considère plus est la lisibilité et la maintenabilité du code. De ce point de vue, je tiens une double Accolade est un meilleur style de code plutôt qu'une méthode statique.

  1. les éléments sont imbriqués et en ligne.
  2. c'est plus OO, pas procédural.
  3. l'impact sur les performances est vraiment petit et pourrait être ignoré.
  4. Meilleur support de contour IDE (plutôt que de nombreux blocs statiques anonymes {})
  5. Vous avez enregistré quelques lignes de commentaire pour les amener relation.
  6. empêcher la fuite d'élément/lead d'instance d'un objet non initialisé de l'optimiseur d'exception et de bytecode.
  7. Ne vous inquiétez pas de l'ordre d'exécution du bloc statique.

En outre, si vous connaissez le GC de la classe anonyme, vous pouvez toujours le convertir en un HashMap normal en utilisant new HashMap(Map map).

Vous pouvez le faire jusqu'à ce que vous rencontriez un autre problème. Si vous le faites, vous devez utiliser un autre style de codage complet (par exemple, pas de statique, classe d'usine) pour cela.

7
répondu Dennis C 2010-12-12 04:29:03

Comme d'habitude, apache-commons a la méthode appropriée MapUtils.putAll (carte, objet[]):

Par exemple, pour créer une carte couleur:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });
7
répondu agad 2016-11-28 07:47:53

Voici mon préféré quand je ne veux pas (ou ne peux pas) utiliser ImmutableMap.of() de goyave, ou si j'ai besoin d'un Map mutable:

public static <A> Map<String, A> asMap(Object... keysAndValues) {
    return new LinkedHashMap<String, A>() {{
        for (int i = 0; i < keysAndValues.length - 1; i++) {
            put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
        }
    }};
}

C'est très compact, et il ignore les valeurs parasites (c'est-à-dire une clé finale sans valeur).

Utilisation:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
5
répondu neu242 2017-06-22 12:34:28

Si vous voulez une carte non modifiable, enfin java 9 a ajouté une méthode d'usine cool of à l'interface Map. Une méthode similaire est également ajoutée à Set, List.

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");

5
répondu Bharanidharan K 2017-11-26 03:38:36

La classe anonyme que vous créez fonctionne bien. Cependant, vous devez être conscient qu'il s'agit d'une classe inner et en tant que telle, elle contiendra une référence à l'instance de classe environnante. Vous trouverez donc que vous ne pouvez pas faire certaines choses avec (en utilisant XStream pour un). Vous obtiendrez des erreurs très étranges.

Cela dit, tant que vous êtes au courant, cette approche est correcte. Je l'utilise la plupart du temps pour initialiser toutes sortes de collections de manière concise.

EDIT: a souligné correctement dans les commentaires qu'il s'agit d'une classe statique. Évidemment, je n'ai pas lu cela assez attentivement. Cependant, mes commentaires Font s'appliquent toujours aux classes internes anonymes.

4
répondu Brian Agnew 2009-02-04 10:21:17

Si vous voulez quelque chose de laconique et relativement sûr, vous pouvez simplement déplacer la vérification de type à la compilation à l'exécution:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

Cette implémentation devrait détecter toutes les erreurs:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}
3
répondu Philip 2013-08-06 20:35:48

Je préfère utiliser un initialiseur statique pour éviter de générer des classes anonymes (ce qui n'aurait pas d'autre but), donc je vais lister des conseils initialisant avec un initialiseur statique. Toutes les solutions / conseils énumérés sont sûrs.

Note: la question ne dit rien à propos de rendre la carte non modifiable, donc je vais laisser cela de côté, mais sachez que cela peut facilement être fait avec Collections.unmodifiableMap(map).

Première astuce

, Le 1er conseil est que vous pouvez faire une référence locale à la carte et vous lui donnez un nom Court:

private static final Map<Integer, String> myMap = new HashMap<>();
static {
    final Map<Integer, String> m = myMap; // Use short name!
    m.put(1, "one"); // Here referencing the local variable which is also faster!
    m.put(2, "two");
    m.put(3, "three");
}

Deuxième astuce

La 2ème astuce est que vous pouvez créer une méthode d'aide à ajouter des entrées; vous pouvez également effectuer cette méthode d'aide publique si vous voulez:

private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
    p(1, "one"); // Calling the helper method.
    p(2, "two");
    p(3, "three");
}

private static void p(Integer k, String v) {
    myMap2.put(k, v);
}

La méthode helper ici n'est pas réutilisable car elle ne peut ajouter que des éléments à myMap2. Pour le rendre réutilisable, nous pourrions faire de la carte elle-même un paramètre de la méthode d'aide, mais le code d'initialisation ne serait pas plus court.

Troisième astuce

Le La 3ème astuce est que vous pouvez créer une classe d'aide réutilisable de type builder avec la fonctionnalité de remplissage. C'est vraiment une classe d'aide simple de 10 lignes qui est sûre de type:

public class Test {
    private static final Map<Integer, String> myMap3 = new HashMap<>();
    static {
        new B<>(myMap3)   // Instantiating the helper class with our map
            .p(1, "one")
            .p(2, "two")
            .p(3, "three");
    }
}

class B<K, V> {
    private final Map<K, V> m;

    public B(Map<K, V> m) {
        this.m = m;
    }

    public B<K, V> p(K k, V v) {
        m.put(k, v);
        return this; // Return this for chaining
    }
}
3
répondu icza 2014-08-28 06:50:05

Avec Java 8, j'en suis venu à utiliser le modèle suivant:

private static final Map<String, Integer> MAP = Stream.of(
    new AbstractMap.SimpleImmutableEntry<>("key1", 1),
    new AbstractMap.SimpleImmutableEntry<>("key2", 2)
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Ce n'est pas le plus laconique et un peu rond-point, mais

  • Il ne nécessite rien en dehors de java.util
  • Il est typesafe et s'adapte facilement à différents types de clé et de valeur.
3
répondu zrvan 2016-06-23 09:14:04

, Vous pouvez utiliser StickyMap et MapEntry à partir de Cactoos:

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);
3
répondu yegor256 2017-07-10 09:09:10

Je n'aime pas la syntaxe d'initialisation statique et je ne suis pas convaincu des sous-classes anonymes. Généralement, je suis d'accord avec tous les inconvénients de l'utilisation d'initialiseurs statiques et tous les inconvénients de l'utilisation de sous-classes anonymes qui ont été mentionnées dans les réponses previus. D'autre part-pros présentés dans ces messages ne sont pas assez pour moi. Je préfère utiliser la méthode d'initialisation statique:

public class MyClass {
    private static final Map<Integer, String> myMap = prepareMap();

    private static Map<Integer, String> prepareMap() {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "one");
        hashMap.put(2, "two");

        return hashMap;
    }
}
2
répondu Stanisław Borowy 2012-08-28 07:00:27

Comme Java ne prend pas en charge les littéraux de carte, les instances de carte doivent toujours être explicitement instanciées et remplies.

Heureusement, il est possible d'approximer le comportement des littéraux de carte en Java en utilisant méthodes d'usine.

Par exemple:

public class LiteralMapFactory {

    // Creates a map from a list of entries
    @SafeVarargs
    public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
        LinkedHashMap<K, V> map = new LinkedHashMap<>();
        for (Map.Entry<K, V> entry : entries) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }
    // Creates a map entry
    public static <K, V> Map.Entry<K, V> entry(K key, V value) {
        return new AbstractMap.SimpleEntry<>(key, value);
    }

    public static void main(String[] args) {
        System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));
    }
}

Sortie:

{a=1, b=2, c=3}

C'est beaucoup plus pratique que de créer et de remplir la carte d'un élément à la fois.

2
répondu nazar_art 2016-02-26 21:53:35

Votre deuxième approche (Double Croisillon d'initialisation) est un anti modèle, donc je pencherais pour la première approche.

Un autre moyen facile d'initialiser une carte statique est d'utiliser cette fonction utilitaire:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {
    Map<K, V> map = new HashMap<>(keyValues.length / 2);

    for (int index = 0; index < keyValues.length / 2; index++) {
        map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);
    }

    return map;
}

Map<Integer, String> map1 = mapOf(1, "value1", 2, "value2");
Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");

Remarque: dans Java 9 vous pouvez utiliser Carte.de

2
répondu R. Oosterholt 2018-04-05 14:52:32

Je n'ai pas vu l'approche que j'utilise (et j'ai grandi à aimer) posté dans toutes les réponses, alors voici:

Je n'aime pas utiliser des initialiseurs statiques car ils sont maladroits, et je n'aime pas les classes anonymes car il crée une nouvelle classe pour chaque instance.

Au lieu de cela, je préfère l'initialisation qui ressemble à ceci:

map(
    entry("keyA", "val1"),
    entry("keyB", "val2"),
    entry("keyC", "val3")
);

Malheureusement, ces méthodes ne font pas partie de la bibliothèque Java standard, vous devrez donc créer (ou utiliser) une bibliothèque utilitaire qui définit le méthodes suivantes:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
 public static <K,V> Map.Entry<K,V> entry(K key, V val)

(Vous pouvez utiliser 'import static' pour éviter d'avoir à préfixer le nom de la méthode)

J'ai trouvé utile de fournir des méthodes statiques similaires pour les autres collections (list, set,sortedSet, sortedMap, etc.)

Ce n'est pas aussi agréable que l'initialisation d'objet json, mais c'est un pas dans cette direction, en ce qui concerne la lisibilité.

1
répondu josh 2015-06-03 20:46:29

JEP 269 fournit des méthodes d'usine de commodité pour L'API Collections. Cette usine méthodes ne sont pas dans la version actuelle de Java, qui est 8, mais sont prévues pour Java 9 Version.

Pour Map il existe deux méthodes de fabrique: of et ofEntries. En utilisant of, vous pouvez passer des paires clé/valeur alternées. Par exemple, pour créer un Map comme {age: 27, major: cs}:

Map<String, Object> info = Map.of("age", 27, "major", "cs");

Actuellement, il existe dix versions surchargées pour of, vous pouvez donc créer une carte contenant dix clés / valeurs pair. Si vous n'aimez pas cette limitation ou l'alternance de clés/valeurs, vous pouvez utiliser ofEntries:

Map<String, Object> info = Map.ofEntries(
                Map.entry("age", 27),
                Map.entry("major", "cs")
);

Les deux of et ofEntries retourneront un Map immuable, donc vous ne pouvez pas changer leurs éléments après la construction. Vous pouvez essayer ces fonctionnalités en utilisant JDK 9 Early Access .

1
répondu Ali Dehghani 2016-04-10 15:37:53

J'ai lu les réponses et j'ai décidé d'écrire mon propre constructeur de cartes. N'hésitez pas à copier-coller et profiter.

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> of(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

EDIT: dernièrement, je continue à trouver la méthode statique publique of assez souvent et je l'aime un peu. Je l'ai ajouté dans le code et rendu le constructeur privé, passant ainsi au modèle de méthode d'usine statique.

1
répondu Vlasec 2016-04-12 17:33:50

Si vous avez seulement besoin d'ajouter une valeur à la carte, vous pouvez utiliser Collections.singletonMap :

Map<K, V> map = Collections.singletonMap(key, value)
1
répondu Stromata 2017-04-30 21:28:08

Eh bien... J'aime les énumérations ;)

enum MyEnum {
    ONE   (1, "one"),
    TWO   (2, "two"),
    THREE (3, "three");

    int value;
    String name;

    MyEnum(int value, String name) {
        this.value = value;
        this.name = name;
    }

    static final Map<Integer, String> MAP = Stream.of( values() )
            .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}
1
répondu jglatre 2017-10-25 16:28:13