Κοινή χρήση τεχνολογίας

Λεπτομερής επεξήγηση του Java Stream API: ένα ισχυρό εργαλείο για αποτελεσματική επεξεργασία δεδομένων συλλογής

2024-07-12

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

εισαγωγή

Η Java 8 εισάγει πολλά νέα χαρακτηριστικά, τα πιο αξιοσημείωτα από τα οποία είναι οι εκφράσεις Lambda και το Stream API. Το Stream API παρέχει μια αποτελεσματική και συνοπτική μέθοδο επεξεργασίας δεδομένων συλλογής, καθιστώντας τον κώδικα πιο συνοπτικό και σαφή και έχει υψηλή αναγνωσιμότητα και δυνατότητα συντήρησης. Αυτό το άρθρο θα εμβαθύνει στη χρήση του Java Stream API, συμπεριλαμβανομένων βασικών εννοιών, κοινών λειτουργιών, παράλληλης επεξεργασίας, πρακτικών περιπτώσεων και βέλτιστων πρακτικών.

Πίνακας περιεχομένων

  1. Τι είναι το Stream API
  2. Βασικές λειτουργίες του Stream API
  3. Προηγμένες λειτουργίες του Stream API
  4. Παράλληλο Ρεύμα
  5. Πρακτική θήκη Stream API
  6. Βέλτιστες πρακτικές για τα API ροής
  7. Συχνές Ερωτήσεις και Λύσεις
  8. Συνοψίζω

Τι είναι το Stream API

Το Stream API είναι μια αφαίρεση που εισήχθη στην Java 8 για την επεξεργασία δεδομένων συλλογής που επιτρέπει την επεξεργασία δεδομένων με δηλωτικό τρόπο (παρόμοιο με τις δηλώσεις SQL). Το Stream API παρέχει πολλές ισχυρές λειτουργίες που μπορούν να χρησιμοποιηθούν για φιλτράρισμα, ταξινόμηση, χαρτογράφηση, μείωση και άλλες λειτουργίες σε συλλογές, απλοποιώντας σημαντικά τον κώδικα.

Χαρακτηριστικά

  • δηλωτικό προγραμματισμό: Χρησιμοποιήστε το Stream API για να γράψετε κώδικα με δηλωτικό τρόπο, μειώνοντας τον κωδικό λέβητα.
  • αλυσιδωτή κλήση: Οι λειτουργίες του Stream API μπορούν να κληθούν σε μια αλυσίδα, βελτιώνοντας την αναγνωσιμότητα του κώδικα.
  • τεμπέλης αξιολόγηση: Οι ενδιάμεσες λειτουργίες αξιολογούνται αργά και αξιολογούνται μόνο όταν εκτελείται η λειτουργία τερματικού.
  • παράλληλη επεξεργασία: Υποστηρίζει παράλληλη επεξεργασία και μπορεί να εκμεταλλευτεί πλήρως τις πολυπύρηνες CPU.

Βασικές λειτουργίες του Stream API

Δημιουργία ροής

Το Stream API παρέχει μια ποικιλία τρόπων για τη δημιουργία μιας ροής, όπως οι παρακάτω:

  1. Δημιουργία από τη συλλογή
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
  • 1
  • 2
  1. Δημιουργία από πίνακα
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
  • 1
  • 2
  1. χρήσηStream.of
Stream<String> stream = Stream.of("a", "b", "c");
  • 1
  1. χρήσηStream.generate
Stream<Double> stream = Stream.generate(Math::random).limit(10);
  • 1
  1. χρήσηStream.iterate
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(10);
  • 1

ενδιάμεσες λειτουργίες

Οι ενδιάμεσες λειτουργίες χρησιμοποιούνται για τη μετατροπή της ροής και αξιολογούνται νωχελικά.

  1. filter: χρησιμοποιείται για το φιλτράρισμα στοιχείων.
Stream<String> stream = list.stream().filter(s -> s.startsWith("a"));
  • 1
  1. map: Χρησιμοποιείται για την αντιστοίχιση κάθε στοιχείου στο αντίστοιχο αποτέλεσμα.
Stream<String> stream = list.stream().map(String::toUpperCase);
  • 1
  1. flatMap: Χρησιμοποιείται για τη μετατροπή κάθε στοιχείου σε ροή και στη συνέχεια τη συγχώνευσή του σε μία ροή.
Stream<String> stream = list.stream().flatMap(s -> Stream.of(s.split("")));
  • 1
  1. distinct: Χρησιμοποιείται για την αφαίρεση διπλότυπων.
Stream<String> stream = list.stream().distinct();
  • 1
  1. sorted: χρησιμοποιείται για ταξινόμηση.
Stream<String> stream = list.stream().sorted();
  • 1
  1. peek: Χρησιμοποιείται για την προβολή κάθε στοιχείου κατά την επεξεργασία.
Stream<String> stream = list.stream().peek(System.out::println);
  • 1

Λειτουργία τερματικού

Οι λειτουργίες τερματικού χρησιμοποιούνται για την έναρξη του υπολογισμού της ροής και τη δημιουργία αποτελεσμάτων Οι συνήθεις λειτουργίες τερματικού περιλαμβάνουν τα ακόλουθα:

  1. forEach: Εκτελέστε μια λειτουργία σε κάθε στοιχείο.
list.stream().forEach(System.out::println);
  • 1
  1. collect: Μετατροπή ροής σε άλλες μορφές.
List<String> result = list.stream().collect(Collectors.toList());
  • 1
  1. reduce: Μειώστε τα στοιχεία στη Ροή σε τιμή.
Optional<String> result = list.stream().reduce((s1, s2) -> s1 + s2);
  • 1
  1. toArray:Μετατροπή ροής σε πίνακα.
String[] array = list.stream().toArray(String[]::new);
  • 1
  1. count: Μετρήστε τον αριθμό των στοιχείων.
long count = list.stream().count();
  • 1
  1. anyMatchallMatchnoneMatch: Χρησιμοποιείται για αντιστοίχιση κρίσης.
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: Χρησιμοποιείται για την εύρεση στοιχείων.
Optional<String> first = list.stream().findFirst();
Optional<String> any = list.stream().findAny();
  • 1
  • 2

Προηγμένες λειτουργίες του Stream API

είδος

χρήσηsortedΗ μέθοδος ταξινομεί τη ροή και μπορεί να περάσει σε έναν συγκριτικό.

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Μέθοδος φιλτραρίσματος στοιχείων στη ροή.

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

χαρτογράφηση

χρήσηmapΗ μέθοδος αντιστοιχίζει στοιχεία στη Ροή.

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

Νόμος

χρήσηreduceΜέθοδος μείωσης των στοιχείων στο Stream.

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

συλλέγω

χρήσηcollectΟι μέθοδοι μετατρέπουν τη ροή σε άλλες μορφές.

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

Παράλληλο Ρεύμα

Το Parallel Stream μπορεί να αξιοποιήσει πλήρως τα πλεονεκτήματα των πολυπύρηνων CPU για τη βελτίωση της αποτελεσματικότητας της επεξεργασίας δεδομένων.μπορεί να χρησιμοποιηθείparallelStreamΗ μέθοδος δημιουργεί παράλληλη ροή.

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

Μπορεί επίσης να χρησιμοποιηθείparallelΗ μέθοδος μετατρέπει μια κανονική ροή σε μια παράλληλη ροή.

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

Πρέπει να σημειωθεί ότι η παράλληλη ροή δεν είναι πάντα ταχύτερη από τη σειριακή ροή και πρέπει να ελεγχθεί ανάλογα με τη συγκεκριμένη κατάσταση.

Πρακτική θήκη Stream API

Επεξεργασία δεδομένων συλλογής

Περίπτωση 1: Φιλτράρισμα και μετατροπή συλλογών

Δεδομένης μιας συλλογής συμβολοσειρών, φιλτράρετε τις συμβολοσειρές των οποίων το μήκος είναι μικρότερο από 3 και μετατρέψτε τις υπόλοιπες συμβολοσειρές σε κεφαλαία.

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
Περίπτωση 2: Υπολογίστε τον μέσο όρο

Δεδομένου ενός συνόλου ακεραίων, υπολογίστε τον μέσο όρο όλων των ακεραίων.

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

Λειτουργίες αρχείων

Περίπτωση 3: Διαβάστε το περιεχόμενο του αρχείου

Χρήση του Stream API

Διαβάστε τα περιεχόμενα του αρχείου και βγείτε στην κονσόλα.

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
Περίπτωση 4: Μετρήστε τον αριθμό των λέξεων που εμφανίζονται

Διαβάστε τα περιεχόμενα του αρχείου και μετρήστε τον αριθμό των εμφανίσεων κάθε λέξης.

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

Λειτουργίες βάσης δεδομένων

Περίπτωση 5: Επεξεργασία αποτελεσμάτων ερωτημάτων βάσης δεδομένων

Ας υποθέσουμε ότι έχουμε έναν πίνακα βάσης δεδομένωνusers, που περιέχει πεδίαidnameκαιage . Μπορούμε να χρησιμοποιήσουμε το Stream API για να επεξεργαστούμε τα αποτελέσματα του ερωτήματος.

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

Βέλτιστες πρακτικές για τα API ροής

  1. Αποφύγετε τον περιττό παραλληλισμό: Η παράλληλη ροή δεν είναι πάντα ταχύτερη και θα πρέπει να επιλέγεται κατά περίπτωση.
  2. Σωστή χρήση των ενδιάμεσων λειτουργιών και των λειτουργιών τερματικού: Οι ενδιάμεσες λειτουργίες αξιολογούνται αργά και αξιολογούνται μόνο όταν εκτελείται η λειτουργία τερματικού.
  3. Δώστε προσοχή στην επαναχρησιμοποίηση του Stream: Μόλις καταναλωθεί μια ροή, δεν μπορεί να χρησιμοποιηθεί ξανά, εάν χρειαστεί να την επαναχρησιμοποιήσετε, μπορείτε να εξετάσετε τη μετατροπή της ροής σε συλλογή πριν τη χρησιμοποιήσετε.
  4. Χρησιμοποιήστε τον κατάλληλο συλλέκτηCollectorsΗ τάξη παρέχει μια ποικιλία συλλεκτών και μπορείτε να επιλέξετε τον κατάλληλο συλλέκτη ανάλογα με τις συγκεκριμένες ανάγκες.
  5. Χειριστείτε τις εξαιρέσεις: Όταν χρησιμοποιείτε το Stream API, πρέπει να χειρίζεστε πιθανές εξαιρέσεις, ειδικά σε λειτουργίες αρχείων και σε λειτουργίες βάσης δεδομένων.

Συχνές Ερωτήσεις και Λύσεις

Η ροή είναι κλειστή

Μόλις καταναλωθεί μια ροή, δεν μπορεί να χρησιμοποιηθεί ξανά, εάν πρέπει να την επαναχρησιμοποιήσετε, μπορείτε να εξετάσετε το ενδεχόμενο μετατροπής της ροής σε συλλογή πριν τη χρησιμοποιήσετε.

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

Ζητήματα επιδόσεων

Οι παράλληλες ροές δεν είναι πάντα ταχύτερες από τις σειριακές ροές και πρέπει να ελέγχονται κατά περίπτωση.μπορεί να χρησιμοποιηθείForkJoinPoolΓια τη βελτιστοποίηση της απόδοσης της παράλληλης ροής.

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

έλλειψη μνήμης

Όταν χρησιμοποιείτε το Stream API για την επεξεργασία μεγάλων ποσοτήτων δεδομένων, πρέπει να δώσετε προσοχή στο πρόβλημα των διαρροών μνήμης.μπορεί να χρησιμοποιηθείcloseμέθοδος για να κλείσετε τη ροή ή να χρησιμοποιήσετεtry-with-resourcesδήλωση κλείνει αυτόματα τη ροή.

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

Συνοψίζω

Αυτό το άρθρο εισάγει λεπτομερώς τη χρήση του Java Stream API, συμπεριλαμβανομένων βασικών λειτουργιών, προηγμένων λειτουργιών, παράλληλης επεξεργασίας, πρακτικών περιπτώσεων και βέλτιστων πρακτικών. Χρησιμοποιώντας ορθολογικά το Stream API, οι προγραμματιστές μπορούν να απλοποιήσουν σημαντικά τον κώδικα, να βελτιώσουν την αναγνωσιμότητα και τη δυνατότητα συντήρησης του κώδικα και επίσης να βελτιώσουν την αποτελεσματικότητα της επεξεργασίας δεδομένων. Ελπίζω ότι αυτό το άρθρο θα σας βοηθήσει στη χρήση του Stream API στην ανάπτυξη Java.

Το Java Stream API είναι ένα ισχυρό εργαλείο για την επεξεργασία δεδομένων συλλογής Μέσω της ευέλικτης χρήσης διαφόρων λειτουργιών, μπορεί να επιτευχθεί αποτελεσματική επεξεργασία δεδομένων και υπολογιστική ροή. Εάν δεν έχετε χρησιμοποιήσει το Stream API, συνιστάται να μάθετε και να κυριαρχήσετε αυτό το ισχυρό εργαλείο το συντομότερο δυνατό και να το εφαρμόσετε στο έργο σας για να βελτιώσετε την αποτελεσματικότητα ανάπτυξης και την ποιότητα του κώδικα.