In diesem Artikel werde ich einige Möglichkeiten vorstellen, um die iterative Verarbeitung unter Verwendung der Datenstruktur von "List" unabhängig von der Implementierung durchzuführen.
Der Inhalt des Artikels entspricht dem gesunden Menschenverstand für diejenigen, die normalerweise Java zum Programmieren verwenden. Die Zielgruppe sind daher Anfänger bis Fortgeschrittene, die gerade mit dem Erlernen von Java begonnen haben. Ich habe jedoch den Eindruck, dass es immer noch wenige Benutzer gibt, die die in JDK 1.8 am Entwicklungsstandort hinzugefügte Methode "forEach" verwenden. Daher möchte ich Sie daran erinnern, wie Sie die Methode "forEach" zu diesem Zeitpunkt verwenden. ..
Beachten Sie, dass dieser Artikel sich mit einfachen Iterationen unter Verwendung der List-Auflistung befasst, sodass wir nicht auf die "Stream-API" eingehen, die Zwischenoperationen wie "Filter" ausführt. Ich möchte die "Stream API" in einem anderen Artikel vorstellen.
--Iterative Verarbeitung mit Listensammlung
get (int)
Seit der Einführung praktischer und effizienter Funktionen wie der Methode "erweitert für Anweisung" und der Methode "forEach" in JDK 1.8 gibt es fast keine Situation, in der die Methode "get" für die Listensammlung verwendet wird und die iterative Verarbeitung mit wahlfreiem Zugriff durchgeführt wird. Ich tat. Dieser Direktzugriff ist jedoch die grundlegendste iterative Methode, die die List-Auflistung verwendet, unabhängig von der Implementierung. Denken Sie also daran, wenn Sie mit Java programmieren.
Die grundlegende Betriebsmethode ist wie folgt.
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++) {
//Holen Sie sich das i-te Element der Variablen (Direktzugriff)
System.out.println(testList.get(i));
}
}
}
Im obigen Beispielcode implementieren wir zuerst eine Testliste, in der drei Elemente als "ArrayList" und als Testwert von "add" gespeichert werden können.
Verwenden Sie danach die Anweisung basic for und wiederholen Sie den Vorgang für die Größe der zuvor erstellten testList
. Im obigen Beispielcode wird die Variable "i" jedes Mal inkrementiert, wenn sie wiederholt wird. Wie Sie im Kommentar sehen können, erfolgt die Verarbeitung von "testList.get (i)" nacheinander für die Elemente von "testList". Es wird zufällig darauf zugegriffen.
Daher wird das Ausführungsergebnis des obigen Beispielcodes wie folgt ausgegeben.
test1
test2
test3
Überprüfen Sie bei Verwendung des Direktzugriffs mit der Methode "get" wie im obigen Beispielcode unbedingt die Größe der Liste, auf die zugegriffen werden soll. Wenn Sie in der Methode "get" einen Index angeben, der größer als die Größe der Zielliste ist, tritt zur Laufzeit immer eine "IndexOutOfBoundsException" auf, und der Prozess schlägt fehl.
Zum Beispiel in den folgenden Fällen.
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");
//Geben Sie einen vierten Index an, der nicht vorhanden ist
testList.get(3);
}
}
Wenn ich den obigen Beispielcode ausführe, erhalte ich die folgende Ausnahme:
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)
Die Größe der Liste, auf die zufällig zugegriffen werden soll, kann mit der Methode "size ()" ermittelt werden, wie im Beispielcode gezeigt, der normal endet. Wenn Sie immer nur einen Datensatz aus der Datenbank basierend auf einem eindeutigen Schlüssel abrufen können, verwenden Sie die Methode "size ()", ohne die Größe der Liste zu überprüfen, z. B. "testList.get (0);" Es ist zulässig, dabei den Zielwert abzurufen.
Der wichtige Punkt ist, den zugänglichen Bereich zu klären, damit "IndexOutOfBoundsException" zur Laufzeit beim Ausführen eines Direktzugriffs nicht auftritt.
Innerhalb der Java List-Sammlung gibt es eine häufig verwendete Datenstruktur namens "LinkedList" sowie "ArrayList". Diese "LinkedList" ist ein Mechanismus, der den Kontext der gespeicherten Elemente mit einem Link enthält, sodass sie zu einer Datenstruktur wird, die zum Einfügen neuer Elemente in das Array und zum Löschen der Elemente im Array geeignet ist.
Der wahlfreie Zugriff auf "LinkedList" weist jedoch die schlechteste Leistung auf. Wenn die Anzahl der Elemente, auf die zufällig zugegriffen werden soll, ungefähr 100 beträgt, ist die Verarbeitungszeit fast dieselbe wie bei Verwendung von "ArrayList", aber mit "LinkedList" wird der zufällige Zugriff für 100.000 oder mehr große Datenmengen wiederholt. Das ist in Bezug auf die Leistung nicht realistisch.
Wenn Sie also umfangreiche Daten mit "LinkedList" durch iterative Verarbeitung verarbeiten, arbeiten Sie mit sequentiellem Zugriff wie "erweitert für Anweisung" und "forEach" -Methode, die später eingeführt wird, anstelle eines Direktzugriffs mit der Methode "get". Bitte geh.
Der folgende Beispielcode für den Direktzugriff wurde bereits früher eingeführt.
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++) {
//Holen Sie sich das i-te Element der Variablen (Direktzugriff)
System.out.println(testList.get(i));
}
}
}
Ich dachte, dass die for-Anweisung im obigen Beispielcode Anfängern möglicherweise nicht vertraut ist, daher werde ich eine Erklärung hinterlassen. Im obigen Beispielcode kann die for-Anweisung wie folgt geschrieben werden.
for (int i = 0; i < testList.size(); i++) {
// do something
}
In dem zu Beginn eingeführten Beispielcode habe ich versucht, die Größe von testList
zu ermitteln, indem ich den Aufruf der size ()
-Methode ausgeführt habe, die sich im Initialisierungsausdrucksteil im bedingten Ausdrucksteil befand.
Sie sollten jedoch vermeiden, die obige for-Anweisung zu schreiben. Da der bedingte Ausdrucksteil "i <testList.size ()" der for-Anweisung bei jeder iterativen Verarbeitung ausgeführt wird, wird im obigen Code die Methode "size ()" durch die Größe von "testList" aufgerufen. Es wird sein. Etwa 10 oder 100 haben nur geringe Auswirkungen auf die Leistung, aber selbst kleine Unterschiede können einen großen Unterschied machen.
Sie können beispielsweise überprüfen, ob die Verarbeitung des bedingten Ausdrucksteils jedes Mal mit dem folgenden Beispielcode ausgeführt wird.
public final class Main {
public static void main(String[] args) throws Exception {
//Stellen Sie sicher, dass der bedingte Ausdrucksteil jedes Mal ausgeführt wird
for (int i = 0; i < 10 && saySomething(); i++) {
// do something
}
}
private static boolean saySomething() {
System.out.println("Hello World!");
return true;
}
}
Das Ausführungsergebnis des obigen Beispielcodes wird wie folgt ausgegeben. Ich würde in meiner normalen Entwicklung keinen Code wie den oben beschriebenen schreiben, aber ich konnte bestätigen, dass die saySomething ()
-Methode des bedingten Ausdrucksteils 10 Mal ausgeführt wurde.
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Hello World!
Aus dem oben Gesagten ist es möglich, ein schlankeres und effizienteres Programm zu schreiben, indem die Anzahl der Fälle ermittelt wird, die im Teil des bedingten Ausdrucks im Teil des Initialisierungsausdrucks verwendet werden sollen, der zu Beginn der for-Anweisung nur einmal ausgeführt wird. Dies ist eine Technik, die nicht nur auf die size ()
-Methode in der List-Sammlung angewendet werden kann, sondern auch auf verschiedene Situationen. Daher möchte ich, dass Menschen, die ein besseres Programm anstreben, jeden Tag daran denken.
Es ist schon eine Weile her, dass die "erweiterte for-Anweisung" als Java-Funktion hinzugefügt wurde, und sie ist bereits zum De-facto-Standard für die sequentielle iterative Verarbeitung von Listensammlungen geworden. Die for-Anweisung ist außerdem einfacher und effizienter als die für den Direktzugriff.
Vor der Einführung der "erweiterten for-Anweisung" wurde ein sequentieller Zugriff erreicht, indem die "Iterator" -Schnittstelle selbst implementiert wurde. Der sequentielle Zugriff mit der "Iterator" -Schnittstelle ist kompliziert und wird häufig implementiert. Er wird selten in älteren Schreibstilen verwendet. Daher werde ich ihn in diesem Artikel nicht im Detail behandeln, sondern als Wissen, bevor "Erweiterung für Anweisung" erscheint Denken Sie daran, dass ich durch die Implementierung der Iterator-Schnittstelle selbst einen sequentiellen Zugriff erzielen konnte.
Darüber hinaus tritt die Leistungsverschlechterung bei Verwendung der "IndexOutOfBoundsException" und "LinkedList", die während des Direktzugriffs mit der "get" -Methode eingeführt wurden, während des sequentiellen Zugriffs mit der "extended for-Anweisung" nicht auf.
Wenn Sie daher die "erweiterte for-Anweisung" verwenden können, wiederholen Sie den Vorgang nicht mit wahlfreiem Zugriff und versuchen Sie, den iterativen Prozess mit der "erweiterten for-Anweisung" zu schreiben.
Wenn Sie nun den Beispielcode für den wahlfreien Zugriff mit der zuvor eingeführten Methode "get" und dem sequentiellen Zugriff mit der erweiterten Anweisung "for" umschreiben, sieht dies wie folgt aus.
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) {
//Holen Sie sich die in testList gespeicherten Werte von Anfang an in der richtigen Reihenfolge
System.out.println(value);
}
}
}
Die Methode zum Lesen der "erweiterten for-Anweisung" im obigen Beispielcode lautet wie folgt: "Rufen Sie die in" testList "gespeicherten Werte von Anfang an in der Reihenfolge" String "ab und speichern Sie sie im Variablennamen" value "." Werden. Die Grammatik ist für andere Hochsprachen wie Python und Ruby ähnlich. Wenn Sie also bereits mit anderen Hochsprachen vertraut sind, sollte es keine besonderen Schwierigkeiten geben.
Das Ausgabeergebnis der Ausführung des obigen Beispielcodes ist wie folgt.
test1
test2
test3
Mit der Einführung der Funktionsschnittstelle in JDK1.8 wurde die Methode "forEach (Consumer
Die grundlegende Schreibmethode ist wie folgt.
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) -> {
//Holen Sie sich die in testList gespeicherten Werte von Anfang an in der richtigen Reihenfolge
System.out.println(value);
});
}
}
Der Punkt, der schwierig erscheint, ist das Argument, aber dem Argument der Methode "forEach ()" wird ein Lambda-Ausdruck übergeben, der die Funktionsschnittstelle "Consumer Consumer <T>
ist eine funktionale Schnittstelle, die die Operation abstrahiert, nur ein Argument zu empfangen und keinen Wert zurückzugeben.
Ich werde den Lambda-Ausdruck und die Funktionsschnittstelle weglassen, da sie vom Zweck dieses Artikels abweichen. Wenn Sie jedoch die Methode forEach ()
in List verwenden, ist es in Ordnung, wenn Sie sich daran erinnern, wie der obige Beispielcode geschrieben wurde.
Das Ausgabeergebnis der Ausführung des obigen Beispielcodes ist wie folgt.
test1
test2
test3
forEach
kann keinen Wert zurückgebenWie bereits in der Erläuterung der Funktionsschnittstelle erwähnt, kann die Methode "forEach" aufgrund der Eigenschaften von "Consumer
[^ 1]: [Java] So erhalten Sie den in Map gespeicherten Schlüssel und Wert durch iterative Verarbeitung