Tuesday, August 29, 2017

Java 8 - Stream

Stream in java 8 is just a interface to better manipulate the collection in a flow /Streamline way , let's see some demos .


Integration Demo 1 - Basics


public static void main(String[] args) {
  
 List<Dish> menu = new ArrayList<>();
 List<Dish> dishes = menu.stream() // convert into Stream Object
    .filter(d -> d.getCalories() > 300) // == if statement
    .limit(3) // == limit the result size
    .skip(2)  // == abandon the first 2 result
    .sorted(...) // sort by asc, can pass a Comparator as well
    .collect(Collectors.toList()); // convert back to list 
    
}

Integration Demo 2 - Map

Map function is to implement such and such a method upon each element in collection.


List<Dish> menu = new ArrayList<>();
List<Integer> dishNameLengths = menu.stream()
    .map(Dish::getName) // retrive each element's name
    .map(String::length) // further retrive each name's length
    .distinct()
    .collect(Collectors.toList());

flatMap function is to implement such and such a method on each element, then combine multiple Stream into one Stream.


List<String> words = new ArrayList<>();
List<String> uniqueCharacters = words.stream()
   .map(w -> w.split("")) // convert into multple Stream<String[]>
   .flatMap(Arrays::stream) // combine into one Stream<String>
   .distinct()
   .collect(Collectors.toList());

Integration Demo 3 - Match & Find

Match & Find is implemented in Java 7 using regular expression, In Java 8 , it gives you more flexbile way to do it . In Stream API, the following functions are provided :

                          allMatch、anyMatch、noneMatch、findFirst  and findAny


public static void main(String[] args) {
 List<Dish> menu = new ArrayList<>();
 // match
 if (menu.stream().anyMatch(Dish::isVegetarian)) { // at least one matched
      System.out.println("matched");
 }
    
 if (menu.stream().allMatch(d -> d.getCalories() < 1000)) { // all matched
      System.out.println("matched");
 }
 if (menu.stream().noneMatch(d -> d.getCalories() >= 1000)) { // none matched
      System.out.println("matched");
 }
}

Optional<T> interface is the return type of Java 8 Match & Find, Becuase If none is found , It may throw NullPointerException,So this Interface is invented to avoid that . It has 4 inherited methods

  • isPresent()  , if something is returned, return true, if nothing is returned, return false. 
  • ifPresent(Consumer<T> block), if somehting is returned, then run a code block.
  • T get(), if something is retured, then get the returned value, else throw NoSuchElementExceptio
  • T orElse(T other), if nothing is returned, it can set a default value and return back. 


Optional<Dish> dish = menu.stream()
  .filter(Dish::isVegetarian)
  .findAny();
  
menu.stream().filter(Dish::isVegetarian)
         .findAny()
         .ifPresent(d -> System.out.println(d.getName())); // if something is returned, 
                                                              then print 
   
List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> firstSquareDivisibleByThree = someNumbers.stream()
   .map(x -> x * x) // inner product of each element
   .filter(x -> x % 3 == 0)
   .findFirst(); // 9

Integration Demo 4 - Reduce

What's reduce? well , you may hear of mapreduce, reducing is a process of summarizing the result or final math computation.


public static void main(String[] args) {
 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
  
 int sum = numbers.stream().reduce(0, (a, b) -> a + b); // get the sum
  
 int product = numbers.stream().reduce(1, (a, b) -> a * b); // get the product
  
 Optional<Integer> max = numbers.stream().reduce(Integer::max); // get the max
  
 Optional<Integer> min = numbers.stream().reduce(Integer::min); // get the min 
  
 List<Dish> menu = new ArrayList<>();
 int count = menu.stream()
  .map(d -> 1)
  .reduce(0, (a, b) -> a + b); // count the total , using mapreduce
}

Integration Demo 6 - Number Steam

Stream is not always the boss , sometimes , when it convert into some primitive types to facilitate some computations , it may face autoboxing and unboxing issues, thus , some his little brothers are invented. IntStream、DoubleStream & LongStream


public static void main(String[] args) {
 List<Dish> menu  = new ArrayList<>();
 int calories = menu.stream()
  .mapToInt(Dish::getCalories) // convert Stream into IntStream
  .sum();
  
 IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
 Stream<Integer> stream = intStream.boxed(); // upgrade IntStream back to Stream
   
 OptionalInt maxCalories = menu.stream()
   .mapToInt(Dish::getCalories)
   .max(); // get the max
 int max = maxCalories.orElse(1); // if no max value, then return 1 as default
  
  
 IntStream evenNumbers = IntStream.rangeClosed(1, 100) // do between 1~100
    .filter(n -> n % 2 == 0);
 System.out.println(evenNumbers.count());
    
    
 Stream<int[]> pythagoreanTriples = IntStream.rangeClosed(1, 100)
                        .boxed() // upgrade to Stream
                        .flatMap(a -> IntStream.rangeClosed(a, 100)
                        .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
                        .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a * a + b * b)})); 
                        // convert primitive type into Object
}

Integration Demo 7 - Create Steam

Stream Creation as we know is from collection. Yes, That's the commonest way. However, There're still some other ways to create a Stream which are not commonly used.
public static void main(String[] args) {
      // created from values 
      Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action"); 
  
      Stream<String> emptyStream = Stream.empty(); // create a empty Stream
  
      int[] numbers = {2, 3, 5, 7, 11, 13};
      int sum = Arrays.stream(numbers).sum(); // created from array
      
      // created from a file 
      Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset()); 
      // created from function iterate() 
      Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println); 
      
      // created from function generate()
      Stream.generate(Math::random).limit(5).forEach(System.out::println); 
  
      IntStream twos = IntStream.generate(new IntSupplier() {
                  public int getAsInt() {
                         return 2;
      }}); // created from code block   
 }


Well , That's all about the guide of Stream. In Next article , I will demostrate how to make use of different Streams to encapsulate a powerful application.


No comments:

Post a Comment

Add Loading Spinner for web request.

when web page is busily loading. normally we need to add a spinner for the user to kill their waiting impatience. Here, 2 steps we need to d...