Dans cet article, je présenterai quelques façons de faire fonctionner le traitement itératif en utilisant la structure de données de List
quelle que soit l'implémentation.
Le contenu de l'article est au niveau du bon sens pour ceux qui programment habituellement en Java, le public cible est donc des débutants aux intermédiaires qui viennent de commencer à apprendre Java. Cependant, j'ai l'impression qu'il y a encore peu de personnes utilisant la méthode forEach
qui a été ajoutée dans JDK 1.8 sur le site de développement, donc j'aimerais que vous vous rappeliez comment utiliser la méthode forEach
pour le moment. ..
Notez que cet article traite des itérations simples à l'aide de la collection List, nous ne parlerons donc pas de l'API Stream
, qui effectue des opérations intermédiaires telles que filtre
. Je voudrais présenter l 'API Stream dans un autre article.
--Traitement itératif à l'aide de la collection List
get (int)
--Accès séquentiel utilisant ʻextended for statement`forEach (Consumer <T>)
(JDK 1.8 ou version ultérieure)get
Depuis l'introduction de fonctions pratiques et efficaces telles que l'instruction ʻextended for et la méthode
forEachdans JDK 1.8, il n'y a presque aucune situation où la méthode
get` est utilisée pour la collection List et le traitement itératif est effectué avec un accès aléatoire. J'ai fait. Cependant, cet accès aléatoire est la méthode itérative la plus basique utilisant la collection List, quelle que soit l'implémentation, alors n'oubliez pas de vous en souvenir si vous programmez avec Java.
La méthode de fonctionnement de base est la suivante.
import java.util.List;
import java.util.ArrayList;
public final class TestGet {
public static void main(String[] args) {
final List<String> testList = new ArrayList<>(3);
testList.add("test1");
testList.add("test2");
testList.add("test3");
for (int i = 0, size = testList.size(); i < size; i++) {
//Récupère le i-ème élément de la variable (accès aléatoire)
System.out.println(testList.get(i));
}
}
}
Dans l'exemple de code ci-dessus, nous implémentons d'abord une liste de test qui peut stocker trois éléments sous la forme ʻArrayList, puis ʻajouter
les valeurs de test.
Après cela, utilisez l'instruction de base pour et répétez le processus pour la taille de testList
préparé plus tôt. Dans l'exemple de code ci-dessus, la variable ʻiest incrémentée à chaque fois qu'elle est répétée, donc comme vous pouvez le voir dans les commentaires, le traitement de
testList.get (i)est exécuté séquentiellement pour les éléments de
testList`. Il sera accessible au hasard.
Par conséquent, le résultat de l'exécution de l'exemple de code ci-dessus est généré comme suit.
test1
test2
test3
Lorsque vous utilisez l'accès aléatoire en utilisant la méthode get
comme dans l'exemple de code ci-dessus, assurez-vous de vérifier la taille de la liste à laquelle accéder. Si vous spécifiez un index plus grand que la taille de la liste cible dans la méthode get
, ʻIndexOutOfBoundsException` (exception hors limites) se produira toujours à l'exécution et le processus échouera.
Par exemple, dans les cas suivants.
import java.util.List;
import java.util.ArrayList;
public final class TestIndexOutOfBoundsException {
public static void main(String[] args) {
final List<String> testList = new ArrayList<>();
testList.add("test1");
testList.add("test2");
testList.add("test3");
//Spécifiez un quatrième index qui n'existe pas
testList.get(3);
}
}
Lorsque j'exécute l'exemple de code ci-dessus, j'obtiens l'exception suivante:
java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:373)
at java.base/java.util.ArrayList.get(ArrayList.java:425)
La taille de la liste à accéder de façon aléatoire peut être obtenue avec la méthode size ()
comme indiqué dans l'exemple de code qui se termine normalement. Si vous pouvez toujours obtenir un seul enregistrement de la base de données basé sur une clé unique, utilisez la méthode size ()
sans vérifier la taille de la liste, comme `testList.get (0); Il est permis d'obtenir la valeur cible dans le processus.
Le point important est de clarifier la plage accessible afin que ʻIndexOutOfBoundsException` ne se produise pas lors de l'exécution lors de l'exécution d'un accès aléatoire.
LinkedList
Dans la collection Java List, il existe une structure de données appelée LinkedList
, qui est également couramment utilisée comme ʻArrayList. Cette
LinkedList` est un mécanisme qui contient le contexte des éléments stockés avec un lien, il devient donc une structure de données appropriée pour insérer de nouveaux éléments dans le tableau et supprimer les éléments dans le tableau.
Cependant, l'accès aléatoire à LinkedList
a les pires performances. Si le nombre d'éléments à accéder de manière aléatoire est d'environ 100, le temps de traitement sera presque le même que lors de l'utilisation de ʻArrayList, mais avec
LinkedList`, l'accès aléatoire est répété pour 100 000 ou plus de données à grande échelle. Ce n'est pas réaliste en termes de performances.
Par conséquent, lorsque vous manipulez des données à grande échelle avec LinkedList
par un traitement itératif, utilisez un accès séquentiel tel que extended for statement
et la méthode forEach
, qui seront introduites plus tard, au lieu d'un accès aléatoire à l'aide de la méthode get
. Pars s'il te plait.
L'exemple de code suivant pour l'accès aléatoire a été introduit plus tôt.
import java.util.List;
import java.util.ArrayList;
public final class TestGet {
public static void main(String[] args) {
final List<String> testList = new ArrayList<>(3);
testList.add("test1");
testList.add("test2");
testList.add("test3");
for (int i = 0, size = testList.size(); i < size; i++) {
//Récupère le i-ème élément de la variable (accès aléatoire)
System.out.println(testList.get(i));
}
}
}
Je pensais que l'instruction for dans l'exemple de code ci-dessus n'était peut-être pas familière aux débutants, je vais donc laisser une explication. Dans l'exemple de code ci-dessus, l'instruction for peut être écrite comme suit.
for (int i = 0; i < testList.size(); i++) {
// do something
}
Dans l'exemple de code introduit au début, j'ai essayé d'obtenir la taille de testList
en exécutant l'appel de la méthode size ()
qui se trouvait dans la partie expression d'initialisation dans la partie expression conditionnelle.
Cependant, vous devez éviter d'écrire la déclaration for ci-dessus. Ceci est dû au fait que la partie expression conditionnelle de l'instruction for ʻi <testList.size () est exécutée à chaque fois qu'un traitement itératif est effectué, donc dans le cas du code ci-dessus, la méthode
size () est appelée par la taille de
testList`. Ce sera. Environ 10 ou 100 auront peu d'impact sur les performances, mais même de petites différences peuvent faire une grande différence.
Par exemple, vous pouvez vérifier que le traitement de la partie d'expression conditionnelle est exécuté à chaque fois avec l'exemple de code suivant.
public final class Main {
public static void main(String[] args) throws Exception {
//Assurez-vous que la partie d'expression conditionnelle est exécutée à chaque fois
for (int i = 0; i < 10 && saySomething(); i++) {
// do something
}
}
private static boolean saySomething() {
System.out.println("Hello World!");
return true;
}
}
Le résultat de l'exécution de l'exemple de code ci-dessus est généré comme suit. Je n'écrirais pas de code comme celui ci-dessus dans mon développement normal, mais j'ai pu confirmer que la méthode saySomething ()
de la partie d'expression conditionnelle a été exécutée 10 fois.
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
À partir de ce qui précède, il est possible d'écrire un programme plus léger et plus efficace en recherchant le nombre d'observations à utiliser dans la partie expression conditionnelle de la partie expression d'initialisation qui n'est exécutée qu'une seule fois au début de l'instruction for. C'est une technique qui peut être appliquée non seulement à la méthode size ()
dans la collection List mais aussi à diverses situations, donc j'aimerais que les personnes qui visent un meilleur programme gardent à l'esprit chaque jour.
Cela fait un moment que l'instruction «étendue for» a été ajoutée en tant que fonctionnalité Java, et elle est déjà devenue la norme de facto pour le traitement itératif séquentiel des collections List. L'instruction for est également plus simple et plus efficace que celle pour l'accès aléatoire.
Avant l'introduction de l'instruction ʻextended for, l'accès séquentiel était réalisé en implémentant l'interface ʻIterator
seule. L'accès séquentiel avec l'interface ʻIterator est compliqué et souvent implémenté, et il est rarement utilisé dans les styles d'écriture hérités, donc je ne le couvrirai pas en détail dans cet article, mais en tant que connaissance, avant l'apparition de ʻextended for statement
Gardez à l'esprit que vous avez pu obtenir un accès séquentiel en implémentant vous-même l'interface ʻIterator`.
De plus, la dégradation des performances lors de l'utilisation de ʻIndexOutOfBoundsException et
LinkedListintroduite lors d'un accès aléatoire à l'aide de la méthode
get ne se produit pas avec un accès séquentiel utilisant l'instruction
extended for`.
Par conséquent, si vous pouvez utiliser l'instruction ʻextended for, ne répétez pas le processus avec un accès aléatoire et essayez d'écrire le processus itératif en utilisant l'instruction
extended for`.
Maintenant, si vous réécrivez l'exemple de code pour un accès aléatoire à l'aide de la méthode get
introduite précédemment avec un accès séquentiel à l'aide de l'instruction extended for
, ce sera comme suit.
import java.util.List;
import java.util.ArrayList;
public final class TestEnhancedForStatement {
public static void main(String[] args) {
final List<String> testList = new ArrayList<>(3);
testList.add("test1");
testList.add("test2");
testList.add("test3");
for (String value : testList) {
//Récupérez les valeurs stockées dans testList dans l'ordre depuis le début
System.out.println(value);
}
}
}
La façon de lire l '«instruction étendue pour» dans l'exemple de code ci-dessus est la suivante: «Récupérez les valeurs stockées dans« testList »en tant que valeurs de type« String »dans l'ordre depuis le début et stockez-les dans le nom de variable« value ».» Devenir. La grammaire est similaire pour d'autres langages de haut niveau tels que Python et Ruby, donc si vous êtes déjà familier avec d'autres langages de haut niveau, il ne devrait y avoir aucune difficulté particulière.
Et le résultat de sortie de l'exécution de l'exemple de code ci-dessus est le suivant.
test1
test2
test3
forEach
Avec l'introduction de l'interface fonctionnelle dans JDK1.8, la méthode forEach (Consumer <T>)
pour manipuler à plusieurs reprises la collection List a été ajoutée. Cette méthode est très similaire à la méthode forEach (BiConsumer <T, U>)
que j'ai introduite plus tôt dans mon article [^ 1] sur l'itération sur des collections de cartes. Il est maintenant possible d'écrire le traitement d'accès séquentiel de manière plus concise et intuitive que l'instruction ʻextended for`.
La méthode d'écriture de base est la suivante.
import java.util.List;
import java.util.ArrayList;
public final class TestForEach {
public static void main(String[] args) {
final List<String> testList = new ArrayList<>(3);
testList.add("test1");
testList.add("test2");
testList.add("test3");
testList.forEach((value) -> {
//Récupérez les valeurs stockées dans testList dans l'ordre depuis le début
System.out.println(value);
});
}
}
Le point qui semble difficile est l'argument, mais l'argument de la méthode forEach ()
reçoit une expression lambda qui implémente l'interface fonctionnelle Consumer <T>
. Consumer <T>
est une interface fonctionnelle qui fait abstraction de l'opération consistant à ne recevoir qu'un seul argument et à ne renvoyer aucune valeur.
J'omettrai l'expression lambda et l'interface fonctionnelle car elles s'écartent de l'objectif de cet article, mais lorsque vous utilisez la méthode forEach ()
dans List, vous pouvez vous rappeler comment écrire l'exemple de code ci-dessus.
Et le résultat de sortie de l'exécution de l'exemple de code ci-dessus est le suivant.
test1
test2
test3
forEach
ne peut pas renvoyer de valeurComme mentionné précédemment dans l'explication de l'interface fonctionnelle, la méthode forEach
ne peut pas renvoyer une valeur en raison des caractéristiques de Consumer <T>
. Par conséquent, si vous souhaitez renvoyer «false» en tant que valeur booléenne lorsqu'une erreur est détectée pendant le traitement itératif de List, envisagez d'utiliser l'instruction «extended for».
[^ 1]: [Java] Comment obtenir la clé et la valeur stockées dans Map par traitement itératif
Recommended Posts