Comment puis-je initialiser une Carte statique?
Comment feriez-vous pour l'initialisation d'un statique Map
en Java?
De la méthode: statique initialiser
Méthode deux: exemple initialiser (anonyme sous-classe)
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");
}
};
}
- Pour l'initialisation d'une carte en Java 8: stackoverflow.com/a/37384773/1216775
- S'il vous plaît, n'utilisez jamais de double croisillon d'initialisation - c'est un hack, et un moyen facile de présenter une fuite de mémoire et causer d'autres problèmes.
- Java 9? Si les entrées de comptage <= 10 utilisation
Map.of
d'autreMap.ofEntries
, consultez stackoverflow.com/a/37384773/1216775
Vous devez vous connecter pour publier un commentaire.
L'instance initialiser est juste sucre syntaxique dans ce cas, non? Je ne vois pas pourquoi vous avez besoin d'un supplément de la classe anonyme juste pour initialiser. Et il ne fonctionnera pas si la classe en cours de création est définitive.
Vous pouvez créer un immuable de la carte en utilisant un statique initialiser trop:
J'aime la Goyave façon d'initialisation statique, immuable carte:
Comme vous pouvez le voir, il est très concis (en raison de la pratique de méthodes de fabrique dans
ImmutableMap
).Si vous voulez la carte à plus de 5 entrées, vous ne pouvez plus utiliser
ImmutableMap.of()
. Au lieu de cela, essayez deImmutableMap.constructeur()
le long de ces lignes:Pour en savoir plus sur les avantages de Goyave immuables de collection, utilitaires, reportez-vous Immuable Collections Expliqué dans la Goyave Guide de l'Utilisateur.
(Un sous-ensemble de) Goyave utilisé pour être appelé Google Collections. Si vous n'êtes pas à l'aide de cette bibliothèque dans votre projet Java et pourtant, je fortement vous recommandons de l'essayer! La goyave est rapidement devenu l'un des plus populaire et utile gratuit 3e partie libs Java, comme compagnons AFIN que les utilisateurs acceptent. (Si vous êtes nouveau à cela, il ya quelques excellentes ressources d'apprentissage derrière ce lien.)
Mise à jour (2015): Comme pour Java 8, bien, je serais encore à utiliser la Goyave approche parce que c'est beaucoup plus propre que toute autre chose. Si vous ne voulez pas de Goyave de dépendance, d'envisager une plaine vieille méthode init. Le hack avec tableau à deux dimensions et des Flux API est assez laid, si vous me demandez, et obtient plus laide 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).Comme pour l'avenir de Goyave en général, en ce qui concerne Java 8, Louis Wasserman dit ce de retour en 2014, et [mise à jour] en 2016, il a été annoncé que Goyave 21 et correctement en charge de Java 8.
Mise à jour (2016): Comme Tagir Valeev souligne, Java 9 vais enfin faire ce propre à faire de l'aide, mais rien de pur JDK, en ajoutant commodité méthodes de fabrique pour les collections:
Java 5 présente cette plus compact de la syntaxe:
HashMap implements Serializable
. Depuis que vous avez fait, créer une sous-classe de la table de hachage à l'aide de ce "truc", vous avez implicitement la création d'une classe Sérialisable. Et pour cela, vous devez fournir un serialUID.Double brace initialization can cause memory leaks when used from a non-static context, because the anonymous class created will maintain a reference to the surrounding object. It has worse performance than regular initialization because of the additional class loading required. It can cause equals() comparisons to fail, if the equals() method does not accept subclasses as parameter. And finally, pre Java 9 it cannot be combined with the diamond operator, because that cannot be used with anonymous classes.
– IntelliJHashMap.equals
est défini dansAbstractMap
et travaille sur aucun sous-classe de la Carte, ce qui n'est pas une préoccupation ici. Le diamant de l'opérateur chose est ennuyeux, mais comme mentionné a été résolu.Serializable
s et (3) sont disposés à maintenir la compatibilité de la forme sérialisée. Lorsque l'une des conditions est fausse, alors vous n'avez pas besoin serialUUID. En particulier, lorsque seulement (1) et (2) ainsi, la valeur par défaut ("missing") serialUUID est parfait.Je voudrais utiliser:
Un avantage de la deuxième méthode est que vous pouvez l'envelopper avec
Collections.unmodifiableMap()
pour garantir que rien ne va mise à jour de la collection plus tard:Voici un Java 8, d'une ligne statique de la carte d'initialiseur:
Edit: pour initialiser un
Map<Integer, String>
comme dans la question, vous auriez besoin de quelque chose comme ceci:Edit(2): Il y a un mieux, mixte-type-version par i_am_zero qui utilise un flux de
new SimpleEntry<>(k, v)
appels. Découvrez cette réponse: https://stackoverflow.com/a/37384773/3950982String[][]
ne le fera pas,Object[][]
est nécessaire). À mon humble avis, cette approche est moche (et encore plus avec le plâtre) et difficiles à retenir, n'est-ce pas l'utiliser moi-même.Map.of
en Java 9+Voir JEP 269 pour plus de détails. JDK 9 atteint la disponibilité générale en septembre 2017.
Map.ofEntries
Map.of(Entry<Integer, String>...)
.Map.ofEntries
.Java 9
Nous pouvons utiliser
Carte.ofEntries
, appelantCarte.entrée( k , v )
pour créer chaque entrée.Nous pouvons également utiliser
Map.of
comme suggéré par Tagir dans sa réponse ici mais on ne peut pas avoir plus de 10 entrées à l'aide deMap.of
.Java 8 (Solution Élégante)
Nous pouvons créer un Flux d'entrées de mappage. Nous avons déjà deux implémentations de
Entry
dansjava.util.AbstractMap
qui sont SimpleEntry et SimpleImmutableEntry. Pour cet exemple, nous pouvons faire appel à d'anciens comme:new SimpleEntry<>()
façon est beaucoup moins lisible que statiqueput()
:/Avec Eclipse Collections, tous les éléments de travail:
Vous pouvez également statiquement initialiser primitive cartes avec Eclipse Collections.
Remarque: je suis un committer pour Eclipse Collections
Je n'aurais jamais créer un anonyme sous-classe dans cette situation. Les initialiseurs statiques fonctionnent aussi bien, si vous souhaitez faire la carte inmodifiable par exemple:
C'est peut-être intéressant de vérifier Google Collections, par exemple, les vidéos qu'ils ont sur leur page. Ils proposent différentes façons d'initialiser les cartes et les jeux, et de fournir immuable des collections.
Mise à jour: Cette bibliothèque est nommé Goyave.
J'aime la classe anonyme, parce qu'il est facile de traiter avec elle:
Si nous déclarer plus d'une constante alors que le code est écrit en statique bloc et qui est difficile à maintenir dans le futur. Il est donc préférable d'utiliser la classe anonyme.
Et il est suggéré d'utiliser unmodifiableMap pour les constantes autres sage, il ne peut pas être traitée comme constante.
Je pourrais vous suggérons fortement de la "double croisillon d'initialisation" style statique bloc de style.
Quelqu'un peut faire des observations qu'ils n'aiment pas la classe anonyme, les frais généraux, les performances, etc.
Mais que j'ai plus considérer est le code de la lisibilité et la maintenabilité. De ce point de vue, j'ai une double croisillon est un meilleur style de code, plutôt que de méthode statique.
En outre, il vous conscient de la GC de la classe anonyme, vous pouvez toujours convertir normal de la table de hachage en utilisant
new HashMap(Map map)
.Vous pouvez le faire jusqu'à ce que vous face à un autre problème. Si vous le faites, vous devez utiliser un autre style de codage (par exemple, pas statique, classe factory) pour elle.
Comme d'habitude apache commons est la bonne méthode MapUtils.putAll(Carte, Object[]):
Par exemple, pour créer une carte de la couleur:
Arrays.asMap( ... )
dans la plaine de Java, je pense que c'est la meilleure solution. Réinventer la roue est généralement ridicule. Très léger inconvénient, c'est qu'avec les médicaments génériques, il aura besoin d'une unchecked conversion.SuppressWarnings( unchecked )
dans Eclipse avec une ligne commeMap<String, String> dummy = MapUtils.putAll(new HashMap<String, String>(), new Object[][]... )
String[][]
je reçois le message d'avertissement""! Et bien sûr, cela ne fonctionne que si votreK
etV
sont de la même classe. - Je prendre, vous n'avez pas (à juste titre) ensemble "unchecked conversion" à "Ignorer" dans votre Eclipse installation?Voici mon préféré quand je ne veux pas (ou ne peut) pas utiliser de Goyave est
ImmutableMap.of()
, ou si j'ai besoin d'une mutableMap
:Il est très compact, et il ignore errants valeurs (c'est à dire une clé finale sans valeur).
Utilisation:
Si vous voulez inmodifiable carte, enfin java 9 ajout d'un cool usine méthode
of
àMap
interface. Une méthode similaire est ajoutée à l'Ensemble, Liste ainsi.Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");
Je préfère utiliser un initialiseur statique pour éviter de générer anonyme classes (qui aurait plus à rien), donc je vais la liste des conseils de l'initialisation avec un initialiseur statique. La liste de toutes les solutions /conseils sont de type sécurisé.
Remarque: La question ne dit rien sur la carte inmodifiable, donc je laisse cela, mais sachez qu'il peut être facilement fait avec
Collections.unmodifiableMap(map)
.Premier conseil
Le 1er conseil est que vous pouvez faire une référence locale à la carte et vous donnez un petit nom:
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:
L'aide de la méthode ici est de ne pas ré-utilisable, car il ne peut ajouter des éléments à
myMap2
. Pour le faire ré-utilisable, nous pourrions faire la carte en elle-même un paramètre de la méthode d'assistance, mais alors le code d'initialisation ne serait pas tout court.Troisième astuce
La 3ème astuce est que vous pouvez créer une ré-utilisable builder-comme la classe helper avec le remplissage de la fonctionnalité. C'est vraiment simple, 10 de ligne de la classe helper qui est de type sécurisé:
La classe anonyme vous êtes en train de créer fonctionne bien. Cependant, vous devriez être conscient que c'est un intérieure classe et en tant que tel, il contiendra une référence à l'environnement instance de classe. Donc, vous vous apercevrez que vous ne pouvez pas faire certaines choses avec elle (à l'aide de XStream pour une). Vous obtiendrez de très étranges erreurs.
Après avoir dit que, tant que vous en êtes conscient, alors cette approche est très bien. Je l'utilise la plupart du temps pour initialisation de toutes sortes de collections dans une présentation concise de la mode.
EDIT: Souligné correctement dans les commentaires que c'est une classe statique. Évidemment, je n'ai pas lu cela d'assez près. Cependant mes commentaires ne sont toujours valables pour les classes internes anonymes.
Si vous voulez quelque chose de concis et relativement sûr, vous pouvez simplement maj au moment de la compilation de vérification de type à l'exécution:
Cette mise en œuvre doit intercepter les erreurs:
Avec Java 8, je viens d'utiliser le modèle suivant:
C'est pas le plus laconique et un peu rond-point, mais
java.util
toMap
signature, y compris un fournisseur de carte de spécifier le type de carte.Si vous avez seulement besoin d'ajouter une valeur à la carte, vous pouvez utiliser Les Collections.singletonMap:
Vous pouvez utiliser
StickyMap
etMapEntry
de Cactoos:Votre deuxième approche (Double Croisillon d'initialisation) est pensé pour être un anti motif, donc je pencherais pour la première approche.
Un autre moyen facile à l'initialisation d'une Carte statique est par l'utilisation de cette fonction d'utilité:
Remarque: dans
Java 9
vous pouvez utiliser Carte.deJe n'aime pas initialiseur Statique de la syntaxe et je ne suis pas convaincu anonyme sous-classes. En général, je suis d'accord avec tous les inconvénients de l'utilisation des initialiseurs Statiques et tous les inconvénients de l'utilisation anonyme sous-classes qui ont été mentionnés dans previus réponses. D'autre part les pros présentés dans ces postes ne sont pas assez pour moi. Je préfère utiliser l'initialisation statique méthode:
Je n'ai pas vu l'approche que j'utilise (et qui ont appris à apprécier) publié dans l'une des réponses, il est donc ici:
Je n'aime pas utiliser les initialiseurs statiques, car ils sont maladroit,
et je n'aime pas les anonymes cours parce qu'il est la création d'une nouvelle classe pour chaque instance.
au lieu de cela, je préfère l'initialisation qui ressemble à ceci:
malheureusement, ces méthodes ne font pas partie de la Java standard de la bibliothèque,
de sorte que vous aurez besoin de créer (ou d'utiliser) une bibliothèque utilitaire qui définit les méthodes suivantes:
(vous pouvez utiliser l'option "importer statique" pour éviter d'avoir à préfixer la méthode de nom)
J'ai trouvé utile d'offrir les mêmes méthodes statiques pour les autres collections (liste, ensemble, sortedSet, sortedMap, etc.)
Ses pas tout à fait aussi beau que json l'initialisation de l'objet, mais c'est un pas dans cette direction, autant que la lisibilité est concerné.
Parce que Java ne prend pas en charge la carte littéraux, carte cas, il doit toujours être instancié explicitement et peuplée.
Heureusement, il est possible d'approximer le comportement de la carte des littéraux en Java à l'aide de usine méthodes.
Par exemple:
De sortie:
Il est beaucoup plus pratique que de créer et de remplir la carte d'un élément à la fois.
JEP 269 fournit certains commodité de l'usine de méthodes pour les Collections de l'API. Cette usine méthodes ne sont pas dans l'actuelle version de Java, qui est de 8, mais qui sont prévus pour Java 9 version.
Pour
Map
il existe deux méthodes de fabrique:of
etofEntries
. À l'aide deof
, vous pouvez passer en alternant paires clé/valeur. Par exemple, afin de créer unMap
comme{age: 27, major: cs}
:Il existe actuellement dix versions surchargées pour
of
, de sorte que vous pouvez créer une carte contenant des dix paires clé/valeur. Si vous n'aimez pas cette limitation ou l'alternance de clés/valeurs, vous pouvez utiliserofEntries
:Les deux
of
etofEntries
sera de retour immuableMap
, de sorte que vous ne pouvez pas modifier leurs éléments après la construction. Vous pouvez essayer ces fonctionnalités à l'aide JDK 9 Accès anticipé.Bien... j'aime les énumérations 😉
J'ai lu les réponses et j'ai décidé d'écrire ma propre map builder. N'hésitez pas à copier-coller et d'en profiter.
EDIT: ces derniers temps, je continue de trouver méthode statique publique
of
assez souvent, et je suis un peu comme elle. Je l'ai ajouté dans le code et fait le constructeur privé, donc de commutation statique méthode de fabrique de modèle.EDIT2: Encore plus récemment, je n'est plus statique méthode appelée
of
, comme il a l'air assez mauvais lors de l'utilisation de statique des importations. Je l'ai renommé pourmapOf
au lieu, de le rendre plus adapté pour la statique des importations.Celui-ci utilise Apache commons-lang qui sera probablement sur votre chemin de classe déjà:
La deuxième méthode peut invoquer les méthodes protected si nécessaire. Cela peut être utile pour l'initialisation des classes qui sont immuables après la construction.
J'aime la classe anonyme de la syntaxe, c'est juste moins de code. Toutefois, une con j'ai trouvé, c'est que vous ne serez pas en mesure de sérialiser l'objet via l'accès distant. Vous aurez une exception au sujet de ne pas être en mesure de trouver la classe anonyme sur le côté éloigné.
J'ai fait quelque chose d'un peu différent. Pas le meilleur, mais cela fonctionne pour moi. Peut-être il pourrait être "généricisés".
Map<Object, Object>
(si l'on peut utiliser une approche analogue avec unString[][]
pourMap<String,String>
et similaire pour les autresMap<T,T>
. Il ne fonctionne pas pour les Cartes où la clé-type est différent de la valeur type.Maintenant que Java 8 est sorti, cette question mérite revoir. J'ai pris un coup de couteau à elle -- ressemble peut-être vous pouvez exploiter la syntaxe de l'expression lambda pour obtenir une très belle et concise (mais type-safe) carte de la syntaxe littérale qui ressemble à ceci:
Non testé exemple de code à https://gist.github.com/galdosd/10823529
Serait curieux sur les opinions des autres sur cela (il est légèrement mal...)
J'ai comme l'utilisation de l'initialiseur statique "technique" quand j'ai une réalisation concrète d'une classe abstraite qui définit une initialisation du constructeur, mais pas de constructeur par défaut, mais je veux que mon sous-classe d'avoir un constructeur par défaut.
Par exemple:
et ma réalisation concrète de cette classe-mais il veut/besoin d'un constructeur par défaut:
puis d'utiliser ce constructeur par défaut, nous n'avons tout simplement:
Dans Java 8, de la procédure d'approche peut également être enveloppé dans
Supplier
:C'est seulement de manière tout à fait hypothétique, mais peut être utile si vous avez vraiment besoin d'un seul-liner.
Si vous pouvez utiliser une représentation de Chaîne de vos données c'est une option trop dans Java 8:
Il y a quelques bonnes réponses ici, mais je tiens à vous offrir un plus.
Créer votre propre méthode statique pour créer et initialiser un
Map
. J'ai ma propreCollectionUtils
classe dans un package que j'utilise pour l'ensemble des projets avec divers utilitaires que j'utilise régulièrement et qui sont faciles pour moi d'écrire et évite la nécessité d'une dépendance à certains des plus grands de la bibliothèque.Voici mon
newMap
méthode:Utilisation:
Il ne fait pas usage des médicaments génériques, mais vous pouvez transtypage de la carte que vous voulez juste être sûr que vous transtypage correctement!)
Même avec la Goyave est agréable ImmutableMap classe, parfois, j'aimerais construire une mutable carte couramment. De me trouver en voulant éviter blocs statiques & anonyme sous-type de chose, lorsque Java 8 est venu le long, j'ai écrit une petite bibliothèque pour aider appelé Couramment.
Avec Java 8 interface défaillante, j'ai pu mettre en œuvre le parler Couramment.Carte de méthodes pour tous les standard de Java Carte implémentations (c'est à dire HashMap, ConcurrentSkipListMap, ... etc) sans fastidieuse répétition.
Inmodifiable cartes sont tout aussi simples.
Voir https://github.com/alexheretic/fluent à la source, de la documentation et des exemples.
Voici le code par AbacusUtil
Déclaration: je suis le développeur de AbacusUtil.
Remarque: la réponse appartient réellement à la question Comment initialiser une table de hachage (au sens propre)? mais puisque c'est marqué doublons de celui-ci...
Avant de Java 9 avec son Carte.de() (qui est également limitée à 10 mappages de), vous pouvez étendre un
Map
mise en œuvre de votre choix, par exemple:ré-implémenter
HashMap
's constructeurs:et ajouter un constructeur qui est inspiré par Aerthel réponse mais est générique en utilisant
Object...
et<K, V>
types:Exécuter
De sortie
Vous pouvez également étendre la
Map
interface de la même manière:Exécuter
De sortie
>>> 1
au lieu de% 2
, hormis le fait qu'elle intentionnellement à confusion?% 2
en conséquence–que je ne sais pas–opérations de décalage sont beaucoup plus performants que des opérations mathématiques, car ils sont mis en œuvre câblé dans n'importe quel CPU, je suis conscient de. 2) Il n'y a que de rares cas où les opérations de décalage peut être utilisé dans les langages de haut niveau, donc je les utilise dès que je peux me rappeler– et d'autres personnes qui lisent mon code qu'ils existent. 3) Il augmente la durée de vie des autres opérateurs en raison de la réduction vieillissement [je plaisante, bien sûr, mais je voulais être trois :]