Stream
1. Sınıfın yöntemlerinin listesi
Sınıf , veri akışı zincirleri oluşturmayıStream
kolaylaştırmak için oluşturuldu . Bunu başarmak için, sınıfın yeni nesneler döndüren yöntemleri vardır .Stream<T>
Stream
Bu veri akışlarının her biri basit bir işlem yapar, ancak bunları zincirler halinde birleştirir ve ilginç lambda işlevleri eklerseniz , istediğiniz çıktıyı oluşturmak için güçlü bir mekanizmaya sahip olursunuz. Yakında kendin göreceksin.
İşte sınıfın yöntemleri Stream
(yalnızca en temel olanlar):
Yöntemler | Tanım |
---|---|
|
Bir dizi nesneden bir akış oluşturur |
|
Belirtilen kurala göre bir akış oluşturur |
|
İki akışı birleştirir |
|
Verileri filtreler, yalnızca belirtilen kuralla eşleşen verileri iletir |
|
Yinelenenleri kaldırır. Halihazırda karşılaşılmış olan verileri iletmez |
|
Verileri sıralar |
|
Akıştaki her öğe üzerinde bir eylem gerçekleştirir |
|
Belirtilen sınırdan daha uzun olmayacak şekilde kesilmiş bir akış döndürür |
|
İlk n elemanı atlar |
|
Verileri bir türden diğerine dönüştürür |
|
Verileri bir türden diğerine dönüştürür |
|
Akışta belirtilen kuralla eşleşen en az bir öğe olup olmadığını kontrol eder |
|
Akıştaki tüm öğelerin belirtilen kuralla eşleşip eşleşmediğini kontrol eder |
|
Akıştaki hiçbir öğenin belirtilen kuralla eşleşmediğini kontrol eder |
|
Bulunan kuralla eşleşen ilk öğeyi döndürür |
|
Akışta kuralla eşleşen herhangi bir öğeyi döndürür |
|
Veri akışındaki minimum öğeyi arar |
|
Veri akışındaki maksimum öğeyi döndürür |
|
Veri akışındaki öğelerin sayısını döndürür |
|
Akıştaki tüm verileri okur ve bir koleksiyon olarak döndürür |
Stream
2. Sınıfa göre ara ve uç işlemler
Gördüğünüz gibi, yukarıdaki tablodaki tüm yöntemler a döndürmez Stream
. Bu, sınıfın yöntemlerinin ara ( terminal olmayan olarak da bilinir ) yöntemler ve uçStream
yöntemler olarak ayrılabilmesi gerçeğiyle ilgilidir .
Ara yöntemler
Ara yöntemler, arabirimi uygulayan bir nesne döndürür Stream
ve birlikte zincirlenebilirler.
Terminal yöntemleri
Terminal yöntemleri a dışında bir değer döndürür Stream
.
Yöntem çağrısı ardışık düzeni
Böylece, herhangi bir sayıda ara yöntemden ve sonunda tek bir terminal yöntemi çağrısından oluşan bir akış işlem hattı oluşturabilirsiniz. Bu yaklaşım, kod okunabilirliğini artırırken oldukça karmaşık mantık uygulamanıza olanak tanır.

Bir veri akışının içindeki veriler hiç değişmez. Ara yöntemler zinciri, uçbirim yöntemi çağrıldıktan sonra yürütülecek bir veri işleme ardışık düzenini belirtmenin kaygan (bildirimsel) bir yoludur.
Yani uçbirim yöntemi çağrılmazsa veri akışındaki veriler hiçbir şekilde işlenmez. Yalnızca terminal yöntemi çağrıldıktan sonra veriler, akış boru hattında belirtilen kurallara göre işlenmeye başlar.
stream()
.intemediateOperation1()
.intemediateOperation2()
...
.intemediateOperationN()
.terminalOperation();
Ara ve terminal yöntemlerin karşılaştırılması:
orta seviye | terminal | |
---|---|---|
Dönüş tipi | Stream |
değilStream |
Bir ardışık düzen oluşturmak için aynı türden birden çok yöntemle birleştirilebilir | Evet | HAYIR |
Tek bir ardışık düzendeki yöntemlerin sayısı | herhangi | birden fazla değil |
Nihai sonucu üretir | HAYIR | Evet |
Akıştaki verileri işlemeye başlar | HAYIR | Evet |
Bir örneğe bakalım.
Diyelim ki hayvanseverler için bir kulübümüz var. Yarın kulüp Ginger Cat Günü'nü kutluyor. Kulübün, her birinin bir evcil hayvan listesi olan evcil hayvan sahipleri vardır. Kedilerle sınırlı değiller.
Görev: Yarının "profesyonel tatili" için onlar için kişiselleştirilmiş tebrik kartları oluşturmak üzere tüm kızıl kedilerin tüm adlarını belirlemeniz gerekir. Tebrik kartları kedinin yaşına göre en yaşlıdan en küçüğe doğru sıralanmalıdır.
İlk olarak, bu görevi çözmeye yardımcı olacak bazı sınıflar sağlıyoruz:
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;
}
}
Selector
Şimdi belirlenen kriterlere göre seçimin yapılacağı sınıfa bakalım :
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);
}
}
Geriye yönteme kod eklemek kalır main
. initData()
Şu anda, ilk önce kulüpteki evcil hayvan sahiplerinin listesini dolduran yöntemi çağırıyoruz . Ardından, yaşlarına göre azalan sırayla sıralanmış kızıl kedilerin isimlerini seçiyoruz.
Öncelikle, bu görevi çözmek için akışları kullanmayan koda bakalım:
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);
}
Şimdi bir alternatife bakalım:
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);
}
Gördüğünüz gibi, kod çok daha derli toplu. Ek olarak, akış boru hattının her satırı tek bir eylemdir, bu nedenle İngilizce cümleler gibi okunabilirler:
|
Stream<Owner> a'dan a'ya taşıStream<Pet> |
|
Veri akışında yalnızca kedileri tut |
|
Veri akışında yalnızca kızıl kedileri tutun |
|
Yaşa göre azalan düzende sırala |
|
İsimleri al |
|
Sonucu bir listeye koyun |
3. Akış oluşturma
Sınıfın Stream
henüz ele almadığımız üç yöntemi var. Bu üç yöntemin amacı yeni iş parçacığı oluşturmaktır.
Stream<T>.of(T obj)
yöntem
Yöntem , tek bir öğeden oluşan bir akışof()
oluşturur . Bu genellikle, örneğin bir işlev bir nesneyi bağımsız değişken olarak aldığında, ancak yalnızca bir nesneniz olduğunda gereklidir . Ardından, tek bir öğeden oluşan bir akış elde etmek için yöntemi kolayca ve basitçe kullanabilirsiniz .Stream<T>
T
of()
Örnek:
Stream<Integer> stream = Stream.of(1);
Stream<T> Stream.of(T obj1, T obj2, T obj3, ...)
yöntem
Yöntem , geçirilen öğelerden oluşan of()
bir akış oluşturur . Herhangi bir sayıda öğeye izin verilir. Örnek:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<T> Stream.generate(Supplier<T> obj)
yöntem
Yöntem generate()
, istendiğinde akışın bir sonraki öğesini oluşturmak için kullanılacak bir kural belirlemenizi sağlar. Örneğin, her seferinde rastgele bir sayı verebilirsiniz .
Örnek:
Stream<Double> s = Stream.generate(Math::random);
Stream<T> Stream.concat(Stream<T> a, Stream<T> b)
yöntem
Yöntem , geçirilen concat()
iki akışı birleştirir . Veriler okunduğunda , önce birinci akıştan sonra ikinci akıştan okunur. Örnek:
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. Verileri filtreleme
Diğer 6 yöntem, yeni veri akışları oluşturarak, akışları değişen karmaşıklıkta zincirler (veya işlem hatları) halinde birleştirmenize olanak tanır.
Stream<T> filter(Predicate<T>)
yöntem
Bu yöntem, kaynak veri akışını geçirilen kurala göre filtreleyen yeni bir veri akışı döndürür . Yöntem , türü olan bir nesnede çağrılmalıdır .Stream<T>
Filtreleme kuralını , derleyicinin daha sonra bir nesneye dönüştüreceği bir lambda işlevi kullanarak belirleyebilirsiniz Predicate<T>
.
Örnekler:
Zincirleme akışlar | Açıklama |
---|---|
|
Yalnızca üçten küçük sayıları saklayın |
|
Yalnızca sıfırdan büyük sayıları koruyun |
Stream<T> sorted(Comparator<T>)
yöntem
Bu yöntem, kaynak akıştaki verileri sıralayan yeni bir veri akışı döndürür . Veri akışının iki öğesini karşılaştırmak için kuralları belirleyen bir karşılaştırıcıyı iletirsiniz .
Stream<T> distinct()
yöntem
Bu yöntem , kaynak veri akışındaki yalnızca benzersiz öğeleri içeren yeni bir veri akışı döndürür . Tüm yinelenen veriler atılır. Örnek:
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>)
yöntem
Bu yöntem , içindeki veriler kaynak akıştakiyle aynı olmasına rağmen yeni bir veri akışı döndürür . Ancak akıştan bir sonraki öğe istendiğinde, yönteme ilettiğiniz işlevpeek()
onunla birlikte çağrılır.
System.out::println
Yönteme işlevi iletirseniz peek()
, tüm nesneler akıştan geçerken görüntülenecektir.
Stream<T> limit(int n)
yöntem
Bu yöntem , kaynak veri akışındaki yalnızca ilk öğeleri içeren yeni bir veri akışı döndürür . Diğer tüm veriler atılır. Örnek:n
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)
yöntem
Bu yöntem, kaynak akışla aynı öğeleri içeren ancak ilk öğeleri atlayan (yok sayan) yeni bir veri akışı döndürür . Örnek:n
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