C, PHP, VB, .NET

Дневникът на Филип Петров


* Статични методи на клас Stream

Публикувано на 16 март 2015 в раздел ПИК3 Java.

В тази статия ще разгледаме статичните методи на клас Stream. Ще покажем и два начина за генериране на безкраен поток – чрез Supplier и чрез метод iterate.

Примерите с код, които ще опишем по-долу се надграждат един-друг. В началото трябва да добавите java.util.function.*, java.util.*, java.text.* и java.util.stream.*.

Stream.builder() създава обект от клас Stream.Builder. Този обект може да акумулира обекти от даден тип и по този начин в последствие да изгражда поток. Методите add и accept добавят елементи (те са напълно еквивалентни), а метод build връща обект от тип Stream.

Stream.Builder<String> strb = Stream.builder();
strb.add("Ivan");
strb.accept("Petar");
strb.add("Maria");
Stream<String> stream1 = strb.build();

Stream.generate(Supplier<T>) – генерира поток на базата на Supplier. Това е безкраен поток, защото Supplier ще връща безкраен брой елементи! Когато работите с такъв поток, трябва в даден момент задължително да използвате short-circuit метод, в противен случай ще се получи безкраен цикъл. В следващият пример генерираме безкраен поток от текущи дата и час, конвертирани в String, след което показваме как може да се чете пореден елемент от този поток:

 // Генерираме дата и час във формат MM/dd/yyyy hh:mm:ss
 // и го предаваме на обект от интерфейс Supplier
 Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 Supplier<String> stringDateSupplier = () -> formatter.format(new Date());
 // Пример, че работи
 System.out.println(stringDateSupplier.get());
 
 // Генерираме безкраен поток
 Stream<String> stream2 = Stream.generate(stringDateSupplier);

Безкрайният поток от дати естествено въобще не е практичен пример. Работата с подобен поток може да генерира много елементи с една и съща дата в рамките на една секунда. Затова го даваме само за демонстрация – не го използвайте никога в практиката.

Stream.concat(Stream<T>, Stream<T>) – обединява два потока от един и същи по тип елементи в общ поток.

 // Обединяваме двата вече създадени потока в един общ
 Stream<String> stream3 = Stream.concat(stream1, stream2);
 
 // Употребяваме short-circuit операция
 Optional<String> getElement = stream3.filter(e -> e.length()>=5).findAny();
 getElement.ifPresent(System.out::println);

Имайте предвид, че в този момент (след употребата на крайната операция върху stream3) вече не можем да използваме не само stream3, но не можем да използваме също stream1 и stream2 – те са вече затворени

Stream.of(T… values) и Stream.of(T t) – генерира поток по подадените параметри.

 // Създаваме два потока от низове с имена на хора
 Stream<String> stream4 = Stream.of("Ivan");
 Stream<String> stream5 = Stream.of("Petar", "Maria");

Stream.empty() – създава нов празен поток (не много смислена операция, но все пак възможна)

Stream<String> stream6 = Stream.empty();
Stream.concat(stream6, Stream.concat(stream4, stream5));

Stream.iterate(T, UnaryOperator<T>) – по подаден seed (първоначална стойност) генерира безкроен поток от елементи по правилото, дефинирано от UnaryOperator-а. В следващият пример създаваме поток от естествени числа и после намираме първите 10 прости.

// Използваме "boxing" - примитивите се конвертират автоматично до Long
Stream<Long> naturalNumbers = Stream.iterate(1L, n -> n + 1);
// Намираме и отпечатваме първите 10 прости числа
naturalNumbers
  .filter(n -> {
     if (n%2==0 || n==1) return false;
     for(int i=3;i*i<=n;i+=2) {
        if(n%i==0) return false;
     }
     return true; 
  })
  .limit(10)
  .forEach(n -> System.out.print(n + " "));

Ето и целият код с всички примери накуп:

import java.util.stream.*;
import java.util.*;
import java.util.function.*;
import java.text.*;

public class StreamExample{
  public static void main(String[] args){
    Stream.Builder<String> strb = Stream.builder();
    strb.add("Ivan");
    strb.accept("Petar");
    strb.add("Maria");
    Stream<String> stream1 = strb.build();
    
    // Генерираме дата и час във формат MM/dd/yyyy hh:mm:ss
    // и го предаваме на обект от интерфейс Supplier
    Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Supplier<String> stringDateSupplier = () -> formatter.format(new Date());
    // Пример, че работи
    System.out.println(stringDateSupplier.get());
    
    // Генерираме безкраен поток
    Stream<String> stream2 = Stream.generate(stringDateSupplier);
    
    // Обединяваме двата вече създадени потока в един общ
    Stream<String> stream3 = Stream.concat(stream1, stream2);
    
    // Употребяваме short-circuit операция
    Optional<String> getElement = stream3.filter(e -> e.length()>=5).findAny();
    getElement.ifPresent(System.out::println);
   
    // Създаваме два потока от низове с имена и факултетни номера на студенти
    Stream<String> stream4 = Stream.of("Ivan");
    Stream<String> stream5 = Stream.of("Petar", "Maria");
    
    Stream<String> stream6 = Stream.empty();
    Stream.concat(stream6, Stream.concat(stream4, stream5));
    
    // Използваме "boxing" - примитивите се конвертират автоматично до Long
    Stream<Long> naturalNumbers = Stream.iterate(1L, n  ->  n  + 1);
    // Намираме и отпечатваме първите 10 прости числа
    naturalNumbers
      .filter(n -> {
          if (n%2==0 || n==1) return false;
          for(int i=3;i*i<=n;i+=2) {
            if(n%i==0) return false;
          }
          return true;      
      })
      .limit(10)
      .forEach(n -> System.out.print(n + " "));
  }
}

 



Добави коментар

Адресът на електронната поща няма да се публикува


*