Technologieaustausch

Ausführliche Erläuterung der Java Stream API: ein leistungsstarkes Tool zur effizienten Verarbeitung von Erfassungsdaten

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Einführung

Java 8 führt viele neue Funktionen ein, die bemerkenswertesten davon sind Lambda-Ausdrücke und die Stream-API. Die Stream-API bietet eine effiziente und präzise Methode zur Verarbeitung von Sammlungsdaten, wodurch der Code präziser und klarer wird und eine hohe Lesbarkeit und Wartbarkeit aufweist. Dieser Artikel befasst sich mit der Verwendung der Java Stream API, einschließlich grundlegender Konzepte, allgemeiner Vorgänge, paralleler Verarbeitung, praktischer Fälle und Best Practices.

Inhaltsverzeichnis

  1. Was ist die Stream-API?
  2. Grundlegende Operationen der Stream-API
  3. Erweiterte Vorgänge der Stream-API
  4. Paralleler Stream
  5. Stream-API-Praxisfall
  6. Best Practices für Stream-APIs
  7. Häufig gestellte Fragen und Lösungen
  8. Zusammenfassen

Was ist die Stream-API?

Die Stream-API ist eine in Java 8 eingeführte Abstraktion zur Verarbeitung von Sammlungsdaten, die eine deklarative Verarbeitung von Daten ermöglicht (ähnlich wie SQL-Anweisungen). Die Stream-API bietet viele leistungsstarke Vorgänge, die zum Filtern, Sortieren, Zuordnen, Reduzieren und anderen Vorgängen für Sammlungen verwendet werden können, wodurch der Code erheblich vereinfacht wird.

Merkmale

  • deklarative Programmierung: Verwenden Sie die Stream-API, um Code deklarativ zu schreiben und so den Boilerplate-Code zu reduzieren.
  • Kettenruf: Die Operationen der Stream-API können in einer Kette aufgerufen werden, was die Lesbarkeit des Codes verbessert.
  • faule Bewertung: Zwischenoperationen werden verzögert ausgewertet und nur dann ausgewertet, wenn die Terminaloperation ausgeführt wird.
  • Parallelverarbeitung: Unterstützt die Parallelverarbeitung und kann die Vorteile von Multi-Core-CPUs voll ausnutzen.

Grundlegende Operationen der Stream-API

Stream erstellen

Die Stream-API bietet verschiedene Möglichkeiten zum Erstellen eines Streams. Zu den häufigsten gehören die folgenden:

  1. Aus Sammlung erstellen
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
  • 1
  • 2
  1. Aus Array erstellen
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
  • 1
  • 2
  1. verwendenStream.of
Stream<String> stream = Stream.of("a", "b", "c");
  • 1
  1. verwendenStream.generate
Stream<Double> stream = Stream.generate(Math::random).limit(10);
  • 1
  1. verwendenStream.iterate
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(10);
  • 1

Zwischenoperationen

Zwischenoperationen werden zum Konvertieren von Stream verwendet und träge ausgewertet. Zu den üblichen Zwischenoperationen gehören die folgenden:

  1. filter: Wird zum Filtern von Elementen verwendet.
Stream<String> stream = list.stream().filter(s -> s.startsWith("a"));
  • 1
  1. map: Wird verwendet, um jedes Element dem entsprechenden Ergebnis zuzuordnen.
Stream<String> stream = list.stream().map(String::toUpperCase);
  • 1
  1. flatMap: Wird verwendet, um jedes Element in einen Stream umzuwandeln und es dann zu einem Stream zusammenzuführen.
Stream<String> stream = list.stream().flatMap(s -> Stream.of(s.split("")));
  • 1
  1. distinct: Wird zum Entfernen von Duplikaten verwendet.
Stream<String> stream = list.stream().distinct();
  • 1
  1. sorted: Wird zum Sortieren verwendet.
Stream<String> stream = list.stream().sorted();
  • 1
  1. peek: Wird verwendet, um jedes Element während der Verarbeitung anzuzeigen.
Stream<String> stream = list.stream().peek(System.out::println);
  • 1

Terminalbetrieb

Terminaloperationen werden verwendet, um die Berechnung von Stream zu starten und Ergebnisse zu generieren. Zu den üblichen Terminaloperationen gehören die folgenden:

  1. forEach: Führen Sie eine Operation für jedes Element aus.
list.stream().forEach(System.out::println);
  • 1
  1. collect: Stream in andere Formen konvertieren.
List<String> result = list.stream().collect(Collectors.toList());
  • 1
  1. reduce: Reduzieren Sie die Elemente im Stream auf einen Wert.
Optional<String> result = list.stream().reduce((s1, s2) -> s1 + s2);
  • 1
  1. toArray:Stream in Array konvertieren.
String[] array = list.stream().toArray(String[]::new);
  • 1
  1. count: Zählen Sie die Anzahl der Elemente.
long count = list.stream().count();
  • 1
  1. anyMatchallMatchnoneMatch: Wird zur Vergleichsbeurteilung verwendet.
boolean anyMatch = list.stream().anyMatch(s -> s.startsWith("a"));
boolean allMatch = list.stream().allMatch(s -> s.startsWith("a"));
boolean noneMatch = list.stream().noneMatch(s -> s.startsWith("a"));
  • 1
  • 2
  • 3
  1. findFirstfindAny: Wird zum Suchen von Elementen verwendet.
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();
  • 1
  • 2

Erweiterte Vorgänge der Stream-API

Sortieren

verwendensortedDie Methode sortiert den Stream und kann einen Komparator übergeben.

List<String> list = Arrays.asList("b", "c", "a");
List<String> sortedList = list.stream().sorted().collect(Collectors.toList());
// 逆序排序
List<String> sortedListDesc = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
  • 1
  • 2
  • 3
  • 4

Filter

verwendenfilterMethode zum Filtern von Elementen in Stream.

List<String> list = Arrays.asList("a", "b", "c");
List<String> filteredList = list.stream().filter(s -> s.startsWith("a")).collect(Collectors.toList());
  • 1
  • 2

Kartierung

verwendenmapMethode ordnet Elemente im Stream zu.

List<String> list = Arrays.asList("a", "b", "c");
List<String> mappedList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
  • 1
  • 2

Satzung

verwendenreduceMethode zum Reduzieren der Elemente im Stream.

List<String> list = Arrays.asList("a", "b", "c");
String result = list.stream().reduce("", (s1, s2) -> s1 + s2);
  • 1
  • 2

sammeln

verwendencollectMethoden konvertieren Stream in andere Formen.

List<String> list = Arrays.asList("a", "b", "c");
List<String> collectedList = list.stream().collect(Collectors.toList());
Set<String> collectedSet = list.stream().collect(Collectors.toSet());
String joinedString = list.stream().collect(Collectors.joining(","));
  • 1
  • 2
  • 3
  • 4

Paralleler Stream

Parallel Stream kann die Vorteile von Multi-Core-CPUs voll ausnutzen, um die Effizienz der Datenverarbeitung zu verbessern.Kann benutzenparallelStreamMethode erstellt parallelen Stream.

List<String> list = Arrays.asList("a", "b", "c");
List<String> parallelList = list.parallelStream().map(String::toUpperCase).collect(Collectors.toList());
  • 1
  • 2

Kann auch benutzt werdenparallelDie Methode wandelt einen normalen Stream in einen parallelen Stream um.

List<String> list = Arrays.asList("a", "b", "c");
List<String> parallelList = list.stream().parallel().map(String::toUpperCase).collect(Collectors.toList());
  • 1
  • 2

Es ist zu beachten, dass der parallele Stream nicht immer schneller ist als der serielle Stream und je nach Situation getestet werden muss.

Stream-API-Praxisfall

Verarbeitung von Erhebungsdaten

Fall 1: Sammlungen filtern und transformieren

Filtern Sie aus einer Sammlung von Zeichenfolgen Zeichenfolgen heraus, deren Länge weniger als 3 beträgt, und konvertieren Sie die verbleibenden Zeichenfolgen in Großbuchstaben.

List<String> list = Arrays.asList("a", "ab", "abc", "abcd");
List<String> result = list.stream()
    .filter(s -> s.length() >= 3)
    .map(String::toUpperCase)
    .collect(Collectors.toList());
System.out.println(result); // 输出:[ABC, ABCD]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
Fall 2: Berechnen Sie den Durchschnitt

Berechnen Sie bei einer gegebenen Menge ganzer Zahlen den Durchschnitt aller ganzen Zahlen.

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
OptionalDouble average = list.stream()
    .mapToInt(Integer::intValue)
    .average();
average.ifPresent(System.out::println); // 输出:3.0
  • 1
  • 2
  • 3
  • 4
  • 5

Dateioperationen

Fall 3: Dateiinhalt lesen

Verwenden der Stream-API

Lesen Sie den Dateiinhalt und geben Sie ihn an die Konsole aus.

try (Stream<String> lines = Files.lines(Paths.get("example.txt"))) {
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
  • 1
  • 2
  • 3
  • 4
  • 5
Fall 4: Zählen Sie die Anzahl der Wortvorkommen

Lesen Sie den Inhalt der Datei und zählen Sie, wie oft jedes Wort vorkommt.

try (Stream<String> lines = Files.lines(Paths.get("example.txt"))) {
    Map<String, Long> wordCount = lines
        .flatMap(line -> Arrays.stream(line.split("\W+")))
        .collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting()));
    wordCount.forEach((word, count) -> System.out.println(word + ": " + count));
} catch (IOException e) {
    e.printStackTrace();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Datenbankoperationen

Fall 5: Verarbeitung von Datenbankabfrageergebnissen

Nehmen wir an, wir haben eine Datenbanktabelleusers, Felder enthaltendidnameUndage . Wir können die Stream-API verwenden, um die Abfrageergebnisse zu verarbeiten.

List<User> users = queryDatabase();
List<String> names = users.stream()
    .filter(user -> user.getAge() > 18)
    .map(User::getName)
    .collect(Collectors.toList());
System.out.println(names);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Best Practices für Stream-APIs

  1. Vermeiden Sie unnötige Parallelisierung: Parallel Stream ist nicht immer schneller und sollte von Fall zu Fall ausgewählt werden.
  2. Ordnungsgemäße Verwendung von Zwischenoperationen und Terminaloperationen: Zwischenoperationen werden verzögert ausgewertet und nur dann ausgewertet, wenn die Terminaloperation ausgeführt wird.
  3. Achten Sie auf die Wiederverwendbarkeit von Stream: Sobald ein Stream verbraucht ist, kann er nicht erneut verwendet werden. Wenn Sie ihn wiederverwenden müssen, können Sie erwägen, den Stream vor der Verwendung in eine Sammlung umzuwandeln.
  4. Verwenden Sie den richtigen KollektorCollectorsDie Klasse bietet eine Vielzahl von Sammlern, und Sie können den passenden Sammler entsprechend Ihren spezifischen Anforderungen auswählen.
  5. Behandeln Sie Ausnahmen: Bei Verwendung der Stream-API müssen Sie mögliche Ausnahmen behandeln, insbesondere bei Dateivorgängen und Datenbankvorgängen.

Häufig gestellte Fragen und Lösungen

Stream ist geschlossen

Sobald ein Stream verbraucht ist, kann er nicht erneut verwendet werden. Wenn Sie ihn wiederverwenden müssen, können Sie erwägen, den Stream vor der Verwendung in eine Sammlung umzuwandeln.

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // 会抛出IllegalStateException
  • 1
  • 2
  • 3
  • 4

Performance-Probleme

Parallele Streams sind nicht immer schneller als serielle Streams und müssen von Fall zu Fall getestet werden.Kann benutzenForkJoinPoolUm die Leistung des parallelen Streams zu optimieren.

ForkJoinPool customThreadPool = new ForkJoinPool(4);
customThreadPool.submit(() ->
    list.parallelStream().forEach(System.out::println)
).get();
  • 1
  • 2
  • 3
  • 4

Speicherleck

Wenn Sie die Stream-API zur Verarbeitung großer Datenmengen verwenden, müssen Sie auf das Problem von Speicherverlusten achten.Kann benutzencloseMethode zum Schließen des Streams oder verwendentry-with-resourcesDie Anweisung schließt den Stream automatisch.

try (Stream<String> lines = Files.lines(Paths.get("example.txt"))) {
    lines.forEach(System.out::println);
} catch (IOException e) {
    e.printStackTrace();
}
  • 1
  • 2
  • 3
  • 4
  • 5

Zusammenfassen

In diesem Artikel wird die Verwendung der Java Stream API ausführlich vorgestellt, einschließlich grundlegender Vorgänge, erweiterter Vorgänge, Parallelverarbeitung, praktischer Fälle und Best Practices. Durch die rationelle Nutzung der Stream-API können Entwickler den Code erheblich vereinfachen, die Lesbarkeit und Wartbarkeit des Codes verbessern und auch die Effizienz der Datenverarbeitung verbessern. Ich hoffe, dass dieser Artikel Ihnen bei der Verwendung der Stream-API in der Java-Entwicklung hilfreich sein wird.

Die Java Stream API ist ein leistungsstarkes Tool zur Verarbeitung von Erfassungsdaten. Durch den flexiblen Einsatz verschiedener Vorgänge können effiziente Datenverarbeitung und Streaming-Computing erreicht werden. Wenn Sie die Stream-API noch nicht verwendet haben, wird empfohlen, dieses leistungsstarke Tool so schnell wie möglich zu erlernen und zu beherrschen und es auf Ihr Projekt anzuwenden, um die Entwicklungseffizienz und Codequalität zu verbessern.