Je veux créer une liste d'options à des fins de test. Au début, j'ai fait ceci:
ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");
Puis j'ai refacturé le code comme suit:
ArrayList<String> places = new ArrayList<String>(
Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
Y a-t-il une meilleure manière de faire cela?
En fait, probablement le "meilleur" moyen d'initialiser le ArrayList
est la méthode que vous avez écrite, car elle n'a pas besoin de créer une nouvelle List
de quelque manière que:
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
Le hic, c'est qu'il y a pas mal de dactylographie nécessaire pour se référer à ça list
exemple.
Il existe des alternatives, telles que la création d'une classe interne anonyme avec un initialiseur d'instance (également appelée "initialisation double accolade"):
ArrayList<String> list = new ArrayList<String>() {{
add("A");
add("B");
add("C");
}};
Cependant, je ne suis pas très friands de cette méthode parce que ce que vous finissez avec est une sous-classe de ArrayList
qui a un initialiseur d'instance, et cette classe est créée juste pour créer un objet - cela me semble un peu exagéré.
Ce qui aurait été bien si le Proposition de Littéraux de Collection pour Pièce de projet a été accepté (il devait être introduit dans Java 7, mais il ne devrait pas non plus faire partie de Java 8):
List<String> list = ["A", "B", "C"];
Malheureusement, cela ne vous aidera pas, car il initialisera un fichier immuable List
plutôt qu'un ArrayList
et, de plus, ce n'est pas encore disponible, si jamais il le sera.
Ce serait plus simple si vous deviez le déclarer comme List
- Doit-il être un ArrayList?
List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
Ou si vous n'avez qu'un seul élément:
List<String> places = Collections.singletonList("Buenos Aires");
Cela signifierait que places
est immuable (essayer de le changer provoquera une UnsupportedOperationException
exception à jeter).
Faire une liste mutable qui soit concrète ArrayList
vous pouvez créer un ArrayList
de la liste immuable:
ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
La réponse simple
En Java 8 ou plus tôt:
List<String> strings = Arrays.asList("foo", "bar", "baz");
Cela vous donnera un List
soutenu par le tableau, de sorte qu'il ne peut pas changer de longueur.
Mais vous pouvez appeler List.set
, donc c'est encore mutable.
En Java 9:
List<String> strings = List.of("foo", "bar", "baz");
Cela vous donnera un immuable List
, donc ça ne peut pas être changé.
C'est ce que vous voulez dans la plupart des cas où vous le précalculez.
La réponse la plus courte
Tu peux faire Arrays.asList
encore plus court avec une importation statique:
List<String> strings = asList("foo", "bar", "baz");
L'importation statique:
import static java.util.Arrays.asList;
Ce que tout IDE moderne vous suggérera et fera automatiquement pour vous.
Par exemple, dans IntelliJ IDEA, vous appuyez sur Alt+Enter
et sélectionnez Static import method...
.
Cependant, je ne recommande pas de raccourcir le Java 9 List.of
méthode, car ayant juste of
devient confus.
List.of
est déjà assez court et se lit bien.
En utilisant Stream
s
Pourquoi est-ce que ça doit être un List
?
Avec Java 8 ou plus tard, vous pouvez utiliser un Stream
ce qui est plus flexible:
Stream<String> strings = Stream.of("foo", "bar", "baz");
Vous pouvez concaténer Stream
s:
Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
Stream.of("baz", "qux"));
Ou vous pouvez aller d'un Stream
à un List
:
List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());
Mais de préférence, utilisez simplement le Stream
sans le collecter à un List
.
Si vous vraiment spécifiquement besoin d'un java.util.ArrayList
(Vous ne le faites probablement pas.)
Citer JEP 269 (Je souligne):
Il y a un petit ensemble de cas d'utilisation pour initialiser une instance de collection mutable avec un ensemble prédéfini de valeurs. Il est généralement préférable d'avoir ces valeurs prédéfinies dans une collection immutable, puis d'initialiser la collection mutable via un constructeur de copie.
Si tu veux tous les deux prépopuler un ArrayList
et ajouter par la suite (pourquoi?), utiliser
List<String> strings = new ArrayList<>(asList("foo", "bar", "baz"));
ou en Java 9:
List<String> strings = new ArrayList<>(List.of("foo", "bar", "baz"));
ou en utilisant Stream
:
List<String> strings = Stream.of("foo", "bar", "baz")
.collect(toCollection(ArrayList::new));
Mais encore une fois, il vaut mieux simplement utiliser le Stream
directement au lieu de le collecter à un List
.
Programme aux interfaces, pas aux implémentations
Vous avez dit que vous avez déclaré la liste comme ArrayList
dans votre code, mais vous ne devriez le faire que si vous utilisez un membre de ArrayList
ce n'est pas dans List
.
Ce que vous ne faites probablement pas.
Habituellement, vous devez simplement déclarer les variables par l'interface la plus générale que vous allez utiliser (par ex. Iterable
, Collection
, ou List
), et les initialiser avec la mise en œuvre spécifique (par ex. ArrayList
, LinkedList
ou Arrays.asList()
).
Sinon, vous limitez votre code à ce type spécifique, et il sera plus difficile de le modifier quand vous le souhaitez.
Par exemple:
// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();
// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>();
// List if you also need .get(index):
List<String> strings = new ArrayList<>();
// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>(); // You don't need ArrayList
Un autre exemple serait toujours la déclaration d'une variable InputStream
même si c'est généralement un FileInputStream
ou un BufferedInputStream
, parce qu'un jour bientôt vous ou quelqu'un d'autre voudra utiliser un autre type de InputStream
.
Si vous avez besoin d'une liste simple de taille 1:
List<String> strings = new ArrayList<String>(Collections.singletonList("A"));
Si vous avez besoin d'une liste de plusieurs objets:
List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");
Avec Goyave tu peux écrire:
ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");
En Guava, il existe également d'autres constructeurs statiques utiles. Vous pouvez lire à leur sujet ici.
Les littéraux de collection ne sont pas inclus dans Java 8, mais il est possible d'utiliser l'API Stream pour initialiser une liste en une ligne plutôt longue:
List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());
Si vous devez vous assurer que votre List
est un ArrayList
:
ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));
import com.google.common.collect.ImmutableList;
....
List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
Vous pouvez créer une méthode d'usine:
public static ArrayList<String> createArrayList(String ... elements) {
ArrayList<String> list = new ArrayList<String>();
for (String element : elements) {
list.add(element);
}
return list;
}
....
ArrayList<String> places = createArrayList(
"São Paulo", "Rio de Janeiro", "Brasília");
Mais ce n'est pas beaucoup mieux que votre premier refactoring.
Pour plus de flexibilité, il peut être générique:
public static <T> ArrayList<T> createArrayList(T ... elements) {
ArrayList<T> list = new ArrayList<T>();
for (T element : elements) {
list.add(element);
}
return list;
}
Avec Java 9
, comme suggéré dans Proposition d'amélioration du JDK - 269, cela pourrait être réalisé en utilisant littéraux de collection maintenant comme -
List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B", "C");
Une approche similaire s'appliquerait également Map
ainsi que -
Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")
qui est similaire à Proposition de Littéraux de Collection comme indiqué par @coobird ainsi. En outre clarifié dans le document JEP -
Alternatives
Les changements de langue ont été considérés plusieurs fois, et rejetés:
Proposition de pièce de projet, 29 mars 2009
Projet de pièce de monnaie, 30 mars 2009
JEP 186 discussion sur lambda-dev, janvier-mars 2014
La langue
propositions ont été mises de côté de préférence à une proposition basée sur une bibliothèque
résumé dans ce message.
Enchaîné lire à peu près le même ~> Quel est le point de surcharge des méthodes Convenience Factory