Stream1. 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
Stream<T> of()
Bir dizi nesneden bir akış oluşturur
Stream<T> generate()
Belirtilen kurala göre bir akış oluşturur
Stream<T> concat()
İki akışı birleştirir
Stream<T> filter()
Verileri filtreler, yalnızca belirtilen kuralla eşleşen verileri iletir
Stream<T> distinct()
Yinelenenleri kaldırır. Halihazırda karşılaşılmış olan verileri iletmez
Stream<T> sorted()
Verileri sıralar
Stream<T> peek()
Akıştaki her öğe üzerinde bir eylem gerçekleştirir
Stream<T> limit(n)
Belirtilen sınırdan daha uzun olmayacak şekilde kesilmiş bir akış döndürür
Stream<T> skip(n)
İlk n elemanı atlar
Stream<R> map()
Verileri bir türden diğerine dönüştürür
Stream<R> flatMap()
Verileri bir türden diğerine dönüştürür
boolean anyMatch()
Akışta belirtilen kuralla eşleşen en az bir öğe olup olmadığını kontrol eder
boolean allMatch()
Akıştaki tüm öğelerin belirtilen kuralla eşleşip eşleşmediğini kontrol eder
boolean noneMatch()
Akıştaki hiçbir öğenin belirtilen kuralla eşleşmediğini kontrol eder
Optional<T> findFirst()
Bulunan kuralla eşleşen ilk öğeyi döndürür
Optional<T> findAny()
Akışta kuralla eşleşen herhangi bir öğeyi döndürür
Optional<T> min()
Veri akışındaki minimum öğeyi arar
Optional<T> max()
Veri akışındaki maksimum öğeyi döndürür
long count()
Veri akışındaki öğelerin sayısını döndürür
R collect()
Akıştaki tüm verileri okur ve bir koleksiyon olarak döndürür

Stream2. 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 Stream yöntemler olarak ayrılabilmesi gerçeğiyle ilgilidir .

Ara yöntemler

Ara yöntemler, arabirimi uygulayan bir nesne döndürür Streamve 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.

Yöntem çağrısı ardışık düzeni

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();
Bir boru hattının genel görünümü

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:

.flatMap(owner -> owner.getPets().stream())
Stream<Owner>a'dan a'ya taşıStream<Pet>
.filter(pet -> Cat.class.equals(pet.getClass()))
Veri akışında yalnızca kedileri tut
.filter(cat -> Color.FOXY == cat.getColor())
Veri akışında yalnızca kızıl kedileri tutun
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
Yaşa göre azalan düzende sırala
.map(Animal::getName)
İsimleri al
.collect(Collectors.toList())
Sonucu bir listeye koyun

3. Akış oluşturma

Sınıfın Streamhenü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>Tof()

Ö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
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x < 3));

Yalnızca üçten küçük sayıları saklayın
Stream<Integer> stream = Stream.of(1, -2, 3, -4, 5);
Stream<Integer> stream2 = stream.filter(x -> (x > 0));

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::printlnYö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