1. Listahan ng mga pamamaraan ng Stream
klase
Nilikha ang Stream
klase upang gawing madali ang pagbuo ng mga chain ng mga stream ng data. Upang makamit ito, ang Stream<T>
klase ay may mga pamamaraan na nagbabalik ng mga bagong Stream
bagay.
Ang bawat isa sa mga stream ng data na ito ay gumagawa ng isang simpleng aksyon, ngunit kung pagsasamahin mo ang mga ito sa mga chain at magdagdag ng mga kawili-wiling mga function ng lambda , kung gayon mayroon kang makapangyarihang mekanismo para sa pagbuo ng output na gusto mo. Sa lalong madaling panahon makikita mo para sa iyong sarili.
Narito ang mga pamamaraan ng Stream
klase (ang pinakapangunahing mga pamamaraan lamang):
Paraan | Paglalarawan |
---|---|
|
Lumilikha ng isang stream mula sa isang hanay ng mga bagay |
|
Bumubuo ng stream ayon sa tinukoy na panuntunan |
|
Pinagsasama ang dalawang batis |
|
Sinasala ang data, nagpapasa lang ng data na tumutugma sa tinukoy na panuntunan |
|
Tinatanggal ang mga duplicate. Hindi nagpapasa ng data na nakatagpo na |
|
Pinag-uuri-uri ang data |
|
Nagsasagawa ng pagkilos sa bawat elemento sa stream |
|
Nagbabalik ng stream na pinutol upang hindi na ito lumampas sa tinukoy na limitasyon |
|
Nilaktawan ang unang n elemento |
|
Kino-convert ang data mula sa isang uri patungo sa isa pa |
|
Kino-convert ang data mula sa isang uri patungo sa isa pa |
|
Sinusuri kung mayroong kahit isang elemento sa stream na tumutugma sa tinukoy na panuntunan |
|
Sinusuri kung ang lahat ng elemento sa stream ay tumutugma sa tinukoy na panuntunan |
|
Sinusuri kung wala sa mga elemento sa stream ang tumutugma sa tinukoy na panuntunan |
|
Ibinabalik ang unang elementong nakita na tumutugma sa panuntunan |
|
Ibinabalik ang anumang elemento sa stream na tumutugma sa panuntunan |
|
Hinahanap ang pinakamababang elemento sa stream ng data |
|
Ibinabalik ang maximum na elemento sa stream ng data |
|
Ibinabalik ang bilang ng mga elemento sa stream ng data |
|
Binabasa ang lahat ng data mula sa stream at ibinabalik ito bilang isang koleksyon |
2. Intermediate at terminal operations ng Stream
klase
Tulad ng nakikita mo, hindi lahat ng mga pamamaraan sa talahanayan sa itaas ay nagbabalik ng Stream
. Ito ay nauugnay sa katotohanan na ang mga pamamaraan ng Stream
klase ay maaaring nahahati sa mga intermediate (kilala rin bilang non-terminal ) na mga pamamaraan at terminal na pamamaraan.
Mga intermediate na pamamaraan
Ang mga intermediate na pamamaraan ay nagbabalik ng isang bagay na nagpapatupad ng Stream
interface, at maaari silang magkakadena.
Mga pamamaraan ng terminal
Ang mga pamamaraan ng terminal ay nagbabalik ng isang halaga maliban sa isang Stream
.
Paraan ng tawag sa pipeline
Kaya, maaari kang bumuo ng isang stream pipeline na binubuo ng anumang bilang ng mga intermediate na pamamaraan at isang solong terminal method na tawag sa dulo. Hinahayaan ka ng diskarteng ito na ipatupad ang medyo kumplikadong lohika, habang pinapataas ang pagiging madaling mabasa ng code.

Ang data sa loob ng isang stream ng data ay hindi nagbabago. Ang isang kadena ng mga intermediate na pamamaraan ay isang makinis (declarative) na paraan ng pagtukoy ng pipeline sa pagpoproseso ng data na isasagawa pagkatapos tawagin ang terminal method.
Sa madaling salita, kung ang paraan ng terminal ay hindi tinatawag, kung gayon ang data sa stream ng data ay hindi naproseso sa anumang paraan. Pagkatapos lamang na tawagin ang paraan ng terminal, magsisimulang maproseso ang data ayon sa mga patakarang tinukoy sa pipeline ng stream.
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
Paghahambing ng mga intermediate at terminal na pamamaraan:
nasa pagitan | terminal | |
---|---|---|
Uri ng pagbabalik | Stream |
hindi aStream |
Maaaring pagsamahin sa maraming paraan ng parehong uri upang bumuo ng pipeline | oo | hindi |
Bilang ng mga pamamaraan sa isang pipeline | anuman | hindi hihigit sa isa |
Gumagawa ng huling resulta | hindi | oo |
Nagsisimulang iproseso ang data sa stream | hindi | oo |
Tingnan natin ang isang halimbawa.
Ipagpalagay na mayroon kaming isang club para sa mga mahilig sa hayop. Bukas ipinagdiriwang ng club ang Ginger Cat Day. Ang club ay may mga may-ari ng alagang hayop, bawat isa ay may listahan ng mga alagang hayop. Hindi sila limitado sa mga pusa.
Gawain: kailangan mong tukuyin ang lahat ng pangalan ng lahat ng luya na pusa upang makagawa ng mga personalized na greeting card para sa kanila para sa "propesyonal na holiday" bukas. Ang mga greeting card ay dapat na pinagsunod-sunod ayon sa edad ng pusa, mula sa pinakamatanda hanggang sa pinakabata.
Una, nagbibigay kami ng ilang klase upang makatulong sa paglutas ng gawaing ito:
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;
}
}
Ngayon tingnan natin ang Selector
klase, kung saan ang pagpili ay gagawin ayon sa tinukoy na pamantayan:
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);
}
}
Ang natitira ay magdagdag ng code sa main
pamamaraan. Sa kasalukuyan, una naming tinawag ang initData()
pamamaraan, na naninirahan sa listahan ng mga may-ari ng alagang hayop sa club. Pagkatapos ay pipiliin namin ang mga pangalan ng luya na pusa na pinagsunod-sunod ayon sa kanilang edad sa pababang pagkakasunud-sunod.
Una, tingnan natin ang code na hindi gumagamit ng mga stream upang malutas ang gawaing ito:
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);
}
Ngayon tingnan natin ang isang alternatibo:
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);
}
Tulad ng nakikita mo, ang code ay mas compact. Bilang karagdagan, ang bawat linya ng stream pipeline ay iisang aksyon, para mabasa ang mga ito tulad ng mga pangungusap sa English:
|
Ilipat mula sa a Stream<Owner> tungo sa aStream<Pet> |
|
Panatilihin lamang ang mga pusa sa stream ng data |
|
Panatilihin lamang ang mga luya na pusa sa stream ng data |
|
Pagbukud-bukurin ayon sa edad sa pababang pagkakasunud-sunod |
|
Kunin ang mga pangalan |
|
Ilagay ang resulta sa isang listahan |
3. Paglikha ng mga stream
Ang Stream
klase ay may tatlong pamamaraan na hindi pa namin sakop. Ang layunin ng tatlong pamamaraang ito ay lumikha ng mga bagong thread.
Stream<T>.of(T obj)
paraan
Ang of()
pamamaraan ay lumilikha ng isang stream na binubuo ng isang solong elemento. Karaniwang kailangan ito kapag, sabihin nating, ang isang function ay tumatagal ng isang Stream<T>
bagay bilang isang argumento, ngunit mayroon ka lamang isang T
bagay. Pagkatapos ay madali at simpleng magagamit mo ang of()
paraan upang makakuha ng stream na binubuo ng isang elemento .
Halimbawa:
Stream<Integer> stream = Stream.of(1);
Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)
paraan
Ang of()
pamamaraan ay lumilikha ng isang stream na binubuo ng mga pumasa na elemento . Ang anumang bilang ng mga elemento ay pinapayagan. Halimbawa:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<T> Stream.generate(Supplier<T> obj)
paraan
Hinahayaan ka ng generate()
paraan na magtakda ng panuntunan na gagamitin para bumuo ng susunod na elemento ng stream kapag hiniling ito. Halimbawa, maaari kang magbigay ng random na numero sa bawat oras.
Halimbawa:
Stream<Double> s = Stream.generate(Math::random);
Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
paraan
Pinagsasama-sama ng concat()
pamamaraan ang dalawang dumaan na stream sa isa . Kapag nabasa ang data , babasahin muna ito mula sa unang stream, at pagkatapos ay mula sa pangalawa. Halimbawa:
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. Pag-filter ng data
Ang isa pang 6 na paraan ay lumikha ng mga bagong stream ng data, na nagpapahintulot sa iyong pagsamahin ang mga stream sa mga chain (o pipeline) na may iba't ibang kumplikado.
Stream<T> filter(Predicate<T>)
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data na nagpi-filter sa source data stream ayon sa ipinasang panuntunan . Ang pamamaraan ay dapat na tinatawag sa isang bagay na ang uri ay Stream<T>
.
Maaari mong tukuyin ang panuntunan sa pag-filter gamit ang isang lambda function , na pagkatapos ay iko-convert ng compiler sa isang Predicate<T>
object.
Mga halimbawa:
Mga nakakadena na sapa | Paliwanag |
---|---|
|
Panatilihin lamang ang mga numerong mas mababa sa tatlo |
|
Panatilihin lamang ang mga numerong mas malaki sa zero |
Stream<T> sorted(Comparator<T>)
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data na nag-uuri ng data sa source stream . Pumasa ka sa isang comparator , na nagtatakda ng mga panuntunan para sa paghahambing ng dalawang elemento ng stream ng data.
Stream<T> distinct()
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data na naglalaman lamang ng mga natatanging elemento sa source data stream . Itatapon ang lahat ng duplicate na data. Halimbawa:
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>)
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data , kahit na ang data sa loob nito ay kapareho ng sa source stream. Ngunit kapag ang susunod na elemento ay hiniling mula sa stream, ang function na ipinasa mo sa peek()
pamamaraan ay tatawagin kasama nito.
Kung ipapasa mo ang function System.out::println
sa peek()
pamamaraan, ang lahat ng mga bagay ay ipapakita kapag sila ay dumaan sa stream.
Stream<T> limit(int n)
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data na naglalaman lamang ng mga unang n
elemento sa source data stream . Ang lahat ng iba pang data ay itinapon. Halimbawa:
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)
paraan
Ang pamamaraang ito ay nagbabalik ng bagong stream ng data na naglalaman ng lahat ng parehong elemento gaya ng source stream , ngunit nilalaktawan (binalewala) ang mga unang n
elemento. Halimbawa:
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