web-dev-qa-db-fra.com

En Java, puis-je déclarer une constante HashMap?

J'écris un programme simple pour convertir un nombre en un mot représentant ce nombre (13 => "treize"). 

Je réalise que je pourrais obtenir certains mots avec un tableau de chaînes constant comme ceci: 

private static final String[] tensNames = {"", " ten", " twenty", " thirty", " forty", " fifty", " sixty", " seventy", " eighty", " ninety" };

... et y accéder avec l'index, mais je voulais l'essayer avec un HashMap comme ceci: 

final HashMap<Integer, String> tensNumberConversion = new HashMap<Integer, String>();
    tensNumberConversion.put(2, "twenty");
    tensNumberConversion.put(3, "thirty");
    tensNumberConversion.put(4, "forty");
    tensNumberConversion.put(5, "fifty");
    tensNumberConversion.put(6, "sixty");
    tensNumberConversion.put(7, "seventy");
    tensNumberConversion.put(8, "eighty");
    tensNumberConversion.put(9, "ninety");

Un enseignant m'a demandé de faire ces constantes. Le HashMap peut-il être une constante? En tant que débutant, la relation entre les termes "constante", "statique" et "final" n'était pas tout à fait claire et ce qui fait exactement une constante. (statique seule? finale seule? finale statique ensemble?).

J'ai essayé de rendre le Hashmap final statique privé mais IntelliJ m'a donné une erreur (le modificateur "privé" n'est pas autorisé ici ... de même pour "statique"). 

Cependant, il compile à partir de mon terminal sans erreur. Si un HashMap peut être une constante, est-ce la bonne façon de le déclarer? Merci!

8
Hoonta

Il y a deux aspects ici:

  • Vous avez une variable qui contient une référence à une carte. Vous déclarez simplement que cette variable est final; Et voilà, vous ne pouvez pas changer la variable pour qu'elle pointe vers une autre référence.
  • Mais cela ne vous empêche pas de changer le state de l'objet pointé par la référence. Ainsi, même lorsque vous avez un objet final Map, vous pouvez toujours appeler des méthodes put/remove/... sur cette carte.

Donc, pour arriver à une vraie carte "constante", vous optez pour ceci:

Tout d'abord, vous créez une carte ordinaire contenant toutes les valeurs souhaitées. 

Ensuite, vous utilisez Collections.unmodifiableMap() afin de créer une carte qui ne peut plus être modifiée. 

La seule chose à laquelle il faut prêter attention: vous devez vous assurer de ne pas laisser fuir une référence à l'objet de la carte d'origine, car cette carte immuable est simplement une enveloppe autour de cette carte initiale. Vous pouvez le faire dans une méthode d'assistance peu, par exemple. 

Si vous demandez: existe-t-il un moyen d'écrire une déclaration de carte sous une "forme littérale" spéciale (comme pour les tableaux) - il n'y en a pas. Eh bien, vous pouvez changer cette méthode d'assistance pour prendre Object ... en tant que paramètre; et ensuite vous passeriez en revue ces paramètres, l’un est un nombre, l’autre une chaîne, et l’utiliser pour remplir la carte. Vous pouvez donc invoquer la méthode avec une seule séquence de valeurs. Mais ça ne vaut probablement pas la peine ...

Une mise à jour rapide: Java9 a ajouté diverses méthodes d’assistance statique qui vous permettent d’écrire des cartes de façon "littérale", voir ici par exemple.

11
GhostCat

Oui, ça peut être une constante. Vous devez déclarer votre instance HashMap comme suit:

class <class name> {
    private static final HashMap<Integer, String> tensNumberConversion = new HashMap<>();

    static {
        tensNumberConversion.put(2, "twenty");
        tensNumberConversion.put(3, "thirty");
        tensNumberConversion.put(4, "forty");
        tensNumberConversion.put(5, "fifty");
        tensNumberConversion.put(6, "sixty");
        tensNumberConversion.put(7, "seventy");
        tensNumberConversion.put(8, "eighty");
        tensNumberConversion.put(9, "ninety");
    }
}

Cependant, il ne s'agit que d'une référence constante. Bien que vous ne puissiez pas réaffecter tensNumberConversion à autre chose, vous pouvez toujours modifier le contenu de votre carte ultérieurement au moment de l'exécution:

tensNumberConversion = new HashMap<>(); // won't compile
tensNumberConversion.put(9, "one"); // succeeds

Si vous souhaitez également que le contenu de votre carte soit constant, vous devez envelopper la HashMap dans une carte non modifiable:

class <class name> {
    private static final Map<Integer, String> tensNumberConversion = initMap();

    private static Map<Integer, String> initMap() {
        Map<Integer, String> map = new HashMap<>();
        map.put(2, "twenty");
        map.put(3, "thirty");
        map.put(4, "forty");
        map.put(5, "fifty");
        map.put(6, "sixty");
        map.put(7, "seventy");
        map.put(8, "eighty");
        map.put(9, "ninety");
        return Collections.unmodifiableMap(map);
    }
}
15
ZhekaKozlov

Juste un BTW, avec Java 9, il existe des méthodes statiques dans l'interface Map pour créer des cartes immuables avec un certain nombre d'entrées comme:

Map<String,String> m = Map.of("k1", "v1",
                              "K2", "v2");

Ou si plus de 10 entrées sont nécessaires:

import static Java.util.Map.entry;
Map<String, String> m = Map.ofEntries(
    entry("k1", "v1"), entry("k2", "v2"), …);
6
eckes

J'ai en quelque sorte manqué la forme la plus facile pour l'initialisation directe de HashMap ici

private static final Map<Integer, String> tensNumberConversion_internal = new HashMap<Integer, String>()
{
    {
        put(2, "twenty");
        put(3, "thirty");
        put(4, "forty");
        put(5, "fifty");
        put(6, "sixty");
        put(7, "seventy");
        put(8, "eighty");
        put(9, "ninety");
    };
};

et comme pour le rendre immuable, vous avez déjà Collections.unmodifiableMap de la réponse acceptée donc

public static final Map<Integer, String> tensNumberConversion = Collections.unmodifiableMap(tensNumberConversion_internal);

ils doivent être créés dans cet ordre de cours;)

1
derHugo

Au lieu d'utiliser le compostage pour obtenir une HashMap constante, vous pouvez utiliser l'héritage pour hériter d'une nouvelle classe de HashMap, puis remplacer la méthode HashMap.put () pour afficher un message d'échec approprié ...

class MyMap extends Java.util.HashMap{
@Override
public V put (K key, V value){
System.out.println("Operation Not Supported");
return null;
}
}

Notez que ce n’est pas la seule méthode mais l’une des nombreuses méthodes possibles.

0
Jagreet