1. Liste over klassens Stream
metoder
Klassen Stream
blev oprettet for at gøre det nemt at konstruere kæder af datastrømme. For at opnå dette Stream<T>
har klassen metoder, der returnerer nye Stream
objekter.
Hver af disse datastrømme udfører en simpel handling, men hvis du kombinerer dem i kæder og tilføjer interessante lambda-funktioner , så har du en kraftfuld mekanisme til at generere det output, du ønsker. Snart vil du se for dig selv.
Her er klassens metoder Stream
(kun de mest basale):
Metoder | Beskrivelse |
---|---|
|
Opretter en strøm fra et sæt objekter |
|
Genererer en strøm i henhold til den angivne regel |
|
Sammenkæder to strømme |
|
Filtrerer dataene og videregiver kun data, der matcher den angivne regel |
|
Fjerner dubletter. Videregiver ikke data, der allerede er stødt på |
|
Sorterer dataene |
|
Udfører en handling på hvert element i strømmen |
|
Returnerer en strøm, der er afkortet, så den ikke er længere end den angivne grænse |
|
Springer de første n elementer over |
|
Konverterer data fra en type til en anden |
|
Konverterer data fra en type til en anden |
|
Kontrollerer, om der er mindst ét element i strømmen, der matcher den angivne regel |
|
Kontrollerer, om alle elementerne i strømmen matcher den angivne regel |
|
Kontrollerer, om ingen af elementerne i strømmen matcher den angivne regel |
|
Returnerer det første fundne element, der matcher reglen |
|
Returnerer ethvert element i strømmen, der matcher reglen |
|
Søger efter minimumselementet i datastrømmen |
|
Returnerer det maksimale element i datastrømmen |
|
Returnerer antallet af elementer i datastrømmen |
|
Læser alle data fra streamen og returnerer dem som en samling |
2. Mellemliggende og terminale operationer af Stream
klassen
Som du kan se, returnerer ikke alle metoder i tabellen ovenfor en Stream
. Dette hænger sammen med, at klassens metoder Stream
kan opdeles i mellemliggende (også kendt som ikke-terminale ) metoder og terminale metoder.
Mellemmetoder
Mellemliggende metoder returnerer et objekt, der implementerer Stream
grænsefladen, og de kan kædes sammen.
Terminal metoder
Terminalmetoder returnerer en anden værdi end en Stream
.
Metodekald pipeline
Således kan du bygge en strømpipeline bestående af et vilkårligt antal mellemliggende metoder og et enkelt terminalmetodekald til sidst. Denne tilgang giver dig mulighed for at implementere temmelig kompleks logik, mens du øger kodelæsbarheden.

Dataene i en datastrøm ændres overhovedet ikke. En kæde af mellemliggende metoder er en smart (deklarativ) måde at specificere en databehandlingspipeline på, som vil blive eksekveret, efter at terminalmetoden er kaldt.
Med andre ord, hvis terminalmetoden ikke kaldes, så behandles dataene i datastrømmen ikke på nogen måde. Først efter at terminalmetoden er kaldt, begynder dataene at blive behandlet i overensstemmelse med de regler, der er specificeret i strømpipelinen.
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
Sammenligning af mellem- og terminalmetoder:
mellemliggende | terminal | |
---|---|---|
Returtype | Stream |
ikke aStream |
Kan kombineres med flere metoder af samme type for at danne en rørledning | Ja | ingen |
Antal metoder i en enkelt pipeline | nogen | ikke mere end én |
Producerer slutresultatet | ingen | Ja |
Begynder at behandle dataene i strømmen | ingen | Ja |
Lad os se på et eksempel.
Antag, at vi har en klub for dyreelskere. I morgen fejrer klubben Ginger Cat Day. Klubben har kæledyrsejere, som hver har en liste over kæledyr. De er ikke begrænset til katte.
Opgave: du skal identificere alle navnene på alle ingefærkattene for at skabe personlige lykønskningskort til dem til morgendagens "professionelle ferie". Lykønskningskortene skal sorteres efter kattens alder, fra ældste til yngste.
Først giver vi nogle klasser for at hjælpe med at løse denne opgave:
public enum Color {
WHITE,
BLACK,
DARK_GREY,
LIGHT_GREY,
FOXY,
GREEN,
YELLOW,
BLUE,
MAGENTA
}
public abstract class Animal {
private String name;
private Color color;
private int age;
public Animal(String name, Color color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal {
public Cat(String name, Color color, int age) {
super(name, color, age);
}
}
public class Dog extends Animal {
public Dog(String name, Color color, int age) {
super(name, color, age);
}
}
public class Parrot extends Animal {
public Parrot(String name, Color color, int age) {
super(name, color, age);
}
}
public class Pig extends Animal {
public Pig(String name, Color color, int age) {
super(name, color, age);
}
}
public class Snake extends Animal {
public Snake(String name, Color color, int age) {
super(name, color, age);
}
}
public class Owner {
private String name;
private List<Animal> pets = new ArrayList<>();
public Owner(String name) {
this.name = name;
}
public List<Animal> getPets() {
return pets;
}
}
Lad os nu se på Selector
klassen, hvor valget vil blive foretaget i henhold til de angivne kriterier:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Selector {
private static List<Owner> owners;
private static void initData() {
final Owner owner1 = new Owner("Ronan Turner");
owner1.getPets().addAll(List.of(
new Cat("Baron", Color.BLACK, 3),
new Cat("Sultan", Color.DARK_GREY, 4),
new Dog("Elsa", Color.WHITE, 0)
));
final Owner owner2 = new Owner("Scarlet Murray");
owner2.getPets().addAll(List.of(
new Cat("Ginger", Color.FOXY, 7),
new Cat("Oscar", Color.FOXY, 5),
new Parrot("Admiral", Color.BLUE, 3)
));
final Owner owner3 = new Owner("Felicity Mason");
owner3.getPets().addAll(List.of(
new Dog("Arnold", Color.FOXY, 3),
new Pig("Vacuum Cleaner", Color.LIGHT_GREY, 8)
));
final Owner owner4 = new Owner("Mitchell Stone");
owner4.getPets().addAll(List.of(
new Snake("Mr. Boa", Color.DARK_GREY, 2)
));
final Owner owner5 = new Owner("Jonathan Snyder");
owner5.getPets().addAll(List.of(
new Cat("Fisher", Color.BLACK, 16),
new Cat("Zorro", Color.FOXY, 14),
new Cat("Margo", Color.WHITE, 3),
new Cat("Brawler", Color.DARK_GREY, 1)
));
owners = List.of(owner1, owner2, owner3, owner4, owner5);
}
}
Tilbage er at tilføje kode til main
metoden. I øjeblikket kalder vi først initData()
metoden, som udfylder listen over kæledyrsejere i klubben. Derefter vælger vi navnene på ingefærkatte sorteret efter deres alder i faldende rækkefølge.
Lad os først se kode, der ikke bruger streams til at løse denne opgave:
public static void main(String[] args) {
initData();
List<String> findNames = new ArrayList<>();
List<Cat> findCats = new ArrayList<>();
for (Owner owner : owners) {
for (Animal pet : owner.getPets()) {
if (Cat.class.equals(pet.getClass()) && Color.FOXY == pet.getColor()) {
findCats.add((Cat) pet);
}
}
}
Collections.sort(findCats, new Comparator<Cat>() {
public int compare(Cat o1, Cat o2) {
return o2.getAge() - o1.getAge();
}
});
for (Cat cat : findCats) {
findNames.add(cat.getName());
}
findNames.forEach(System.out::println);
}
Lad os nu se på et alternativ:
public static void main(String[] args) {
initData();
final List<String> findNames = owners.stream()
.flatMap(owner -> owner.getPets().stream())
.filter(pet -> Cat.class.equals(pet.getClass()))
.filter(cat -> Color.FOXY == cat.getColor())
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
.map(Animal::getName)
.collect(Collectors.toList());
findNames.forEach(System.out::println);
}
Som du kan se, er koden meget mere kompakt. Derudover er hver linje i strømpipelinen en enkelt handling, så de kan læses som sætninger på engelsk:
|
Gå fra a Stream<Owner> til aStream<Pet> |
|
Behold kun katte i datastrømmen |
|
Behold kun ingefærkatte i datastrømmen |
|
Sorter efter alder i faldende rækkefølge |
|
Få navnene |
|
Sæt resultatet på en liste |
3. Oprettelse af streams
Klassen Stream
har tre metoder, som vi ikke har dækket endnu. Formålet med disse tre metoder er at skabe nye tråde.
Stream<T>.of(T obj)
metode
Metoden of()
skaber en strøm , der består af et enkelt element. Dette er normalt nødvendigt, når f.eks. en funktion tager et Stream<T>
objekt som et argument, men du kun har et T
objekt. Så kan du nemt og enkelt bruge of()
metoden til at få en strøm , der består af et enkelt element .
Eksempel:
Stream<Integer> stream = Stream.of(1);
Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)
metode
Metoden of()
opretter en strøm , der består af beståede elementer . Et hvilket som helst antal elementer er tilladt. Eksempel:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<T> Stream.generate(Supplier<T> obj)
metode
Metoden generate()
giver dig mulighed for at indstille en regel, der vil blive brugt til at generere det næste element i strømmen, når det anmodes om det. For eksempel kan du give et tilfældigt tal hver gang.
Eksempel:
Stream<Double> s = Stream.generate(Math::random);
Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
metode
Metoden concat()
sammenkæder de to passerede strømme til én . Når dataene læses, læses de først fra den første strøm og derefter fra den anden. Eksempel:
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = Stream.of(10, 11, 12, 13, 14);
Stream<Integer> result = Stream.concat(stream1, stream2);
4. Filtrering af data
Yderligere 6 metoder skaber nye datastrømme, så du kan kombinere strømme til kæder (eller pipelines) af varierende kompleksitet.
Stream<T> filter(Predicate<T>)
metode
Denne metode returnerer en ny datastrøm , der filtrerer kildedatastrømmen i henhold til den beståede regel . Metoden skal kaldes på et objekt , hvis type er Stream<T>
.
Du kan angive filtreringsreglen ved hjælp af en lambda-funktion , som compileren derefter konverterer til et Predicate<T>
objekt.
Eksempler:
Lænkede vandløb | Forklaring |
---|---|
|
Behold kun tal mindre end tre |
|
Bevar kun tal større end nul |
Stream<T> sorted(Comparator<T>)
metode
Denne metode returnerer en ny datastrøm, der sorterer dataene i kildestrømmen . Du sender en komparator ind , som sætter reglerne for sammenligning af to elementer i datastrømmen.
Stream<T> distinct()
metode
Denne metode returnerer en ny datastrøm , der kun indeholder de unikke elementer i kildedatastrømmen . Alle duplikerede data kasseres. Eksempel:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.distinct(); // 1, 2, 3, 4, 5
Stream<T> peek(Consumer<T>)
metode
Denne metode returnerer en ny datastrøm , selvom dataene i den er de samme som i kildestrømmen. Men når det næste element bliver anmodet om fra strømmen, kaldes den funktion , du sendte til peek()
metoden, med den.
Hvis du videregiver funktionen System.out::println
til peek()
metoden, vil alle objekterne blive vist, når de passerer gennem åen.
Stream<T> limit(int n)
metode
Denne metode returnerer en ny datastrøm , der kunn
indeholder de første elementer i kildedatastrømmen . Alle andre data kasseres. Eksempel:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.limit(3); // 1, 2, 3
Stream<T> skip(int n)
metode
Denne metode returnerer en ny datastrøm , der indeholder alle de samme elementer som kildestrømmen , men springer over (ignorerer) de første n
elementer. Eksempel:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 2, 2, 2, 3, 4);
Stream<Integer> stream2 = stream.skip(3); // 4, 5, 2, 2, 2, 3, 4
GO TO FULL VERSION