Skip to content

Latest commit

 

History

History
209 lines (154 loc) · 6.64 KB

03. Streams API.md

File metadata and controls

209 lines (154 loc) · 6.64 KB

Stream API

  • It is a sequence of elements supporting sequential and parallel aggregate operations.
  • Streams provide new ways of accessing and extracting data from collections.
  • Streams do not mutate their source, rather return new streams that holds the result.
  • Purely functional, so thread safe.
  • Streams operations are lazy whenever possible.

Ways of creating streams

  • By calling stream() method on any collection objects.
  • By Using static method stream.of(), we can get stream from sequence of arguments.

Generate infinite streams

  • Using generate function. It accepts Supplier<T>.
interface Supplier<T> {
   T get();
}

class Main{
    public static void main(String[] args){
        Stream.generate(() -> "Echo").forEach(System.out::println);
    }
}
  • Using iterate function. It accepts a seed value ( of type T ) and a UnaryOperator<T> argument.
interface UnaryOperator<T>{
    T apply(T t);
}

class Main{
    public static void main(String[] args){
        Stream.iterate(1, n -> n + 1).forEach(System.out::println);
    }
}

Primitive Streams

class Main{
    public static void main(String[] args){
        IntStream ints = IntStream.of(1, 2, 4, 8);
        IntStream ones = IntStream.generate(() -> 1);

        Stream<Integer> integers = IntStream.range(0,100).boxed();
    }
}

Stream Operations

  • limit(n) : Returns a new stream that ends after n elements or when original stream ends if it is shorter.
  • skip(n) : Returns a new stream that starts after n elements.
  • Stream.concat(s1,s2) : Returns a new stream after concatenating streams s1 and s2.

Intermediate Stream Operations

  • filter : extract a sub stream that satisfies specified criteria. it accepts a Predicate<T> interface and returns another new stream, thus filters can be chained.
  • map : transforms each element of a stream and returns a new stream.
  • flatMap: transform each element of a sub stream and flatten the result.
class Main{
    public static void main(String[] args){
        Stream.of(1,2,3).flatMap(x-> Stream.of(x,x*x)).forEach( System.out::println);
        // output: 1 1 2 4 3 9
    }
}

Stateful Intermediate Stream Operations

  • skip, limit, distinct and sorted.
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;

class Main {
    public static void main(String[] args) {
        Stream.of(1, 2, 3).skip(2).forEach(System.out::println); // 3
        Stream.of(1, 2, 3).limit(2).forEach(System.out::println); // 1 2
        Stream.of(1, 2, 3, 1, 2).distinct().forEach(System.out::println); // 1 2 3
        Stream.of(1, 2, 3, 1, 2).sorted().forEach(System.out::println); // 1 2 3
        Stream.of(1, 2, 3, 1, 2).sorted((x, y) -> y - x).forEach(System.out::println); // 3 2 2 1 1
        Stream.of(1, 2, 3, 1, 2).sorted(Comparator.naturalOrder()).forEach(System.out::println);
        Stream.of(1, 2, 3, 1, 2).sorted((x, y) -> x - y).forEach(System.out::println); // 1 1 2 2 3
        Stream.of(1, 2, 3, 1, 2).sorted(Comparator.reverseOrder()).forEach(System.out::println);


        List<String> words= Arrays.asList("Tom", "Joseph", "Richard");
        words.stream().sorted((x, y) -> x.length() - y.length()).forEach(System.out::println);
        words.stream().sorted(Comparator.comparingInt(String::length).reversed()).forEach(System.out::println);
        words.stream().sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
    }
}

Terminal Stream Operations

  • Once, terminal operations are called on streams, streams are terminated.

  • a.k.a reduction methods because they reduce the stream to some final value.

  • collect, count, max, min, findFirst, findAny, reduce :

class Main{
    public static void main(String[] args){
        List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());

        long count  = list.stream().filter((x) -> x > 1).count();

        Optional<Integer> max  = list.stream().max(Integer::compare);
        Optional<Integer> min  = list.stream().min(Integer::compare);

        Optional<Integer> first  = list.stream().findFirst();
        Optional<Integer> any  = list.stream().findAny();
        
    }
}
  • Reduce:
    • first argument is the initial value. This is the value that is returned if the stream is empty and is the starting point for the computation.
      • second argument is the lambda of type BinaryOperator<T>

        interface BinaryOperator<T> {
            T apply(T a, T b);
        }
        
        public class Test {
        
            public static void main(String[] args){
                List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());
        
                int sum = list.stream().reduce(0,(x,y)->x+y);
                Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y);
                System.out.println(sum);
            }
        }

Collecting results ( Terminal Operations )

import javax.swing.text.html.parser.TagElement;
import java.util.stream.Collectors;

class Person {
    public int id;
    public String name;
    public int age;

    Person(int id, String name, int age) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}

class Main {
    public static void main(String[] args) {
        List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());
        Set<Integer> set = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toSet());

        Stream<Person> personStream = Stream.of(new Person(1,"Bob",28),new Person(2,"Ben",29));
        Map<Integer, String> idToName = personStream.collect(Collectors.toMap(Person::getId, Person::getName));

        
        Map<Integer, Person> idToPerson = personStream.collect(Collectors.toMap(Person::getId, Function.identity()));
    }
}

identity is a static method on Function that returns a function that always returns its input argument. In the example, it is the function (Person p) -> p

working with Optional class

  • Optionals are a way to handle null values.
class Main{
    public static void main(String[] args){
        List<Integer> list = Stream.of(1, 2, 3, 1, 2).sorted(Integer::compare).collect(Collectors.toList());

        long count  = list.stream().filter((x) -> x > 1).count();

        Optional<Integer> max  = list.stream().max(Integer::compare);
        if(max.isPresent()){
            System.out.println(max.get());
        }
    }
}
  • using orElse OptionalValue.orElse(defaultValue)
  • ifPresent(Consumer) OptionalValue.ifPresent(v-> System.out.println(v))