Reactive Programming with Java 8
--j---a--v--a---r----x----|
What is Reactive Programming?

“a paradigm that revolves around the propagation of change”

"propagating all the changes that modifies data to all the interested parties"

"EventBus or notification center on Steroids"

A

B

C

a

b

SUM(A, B)

Imperative Solution

int a = 4;

int b = 5;

int c = a + b;

b = 7;

Reactive Solution

'c' tracks changes in 'a' and 'b' and reacts to those changes by

updating its own value based on the relation 'c = a+b'

Reactive manifesto

Modular

Scalable

Resilient

Responsive

Reactive manifesto

Modular

Scalable

Resilient

Responsive

Event Driven

Streams
--j---a--v--a---r----x----|

"any data source can be viewed as streams of values over time or space"

A stream has three kind of values that an Observer can react to

'Value', 'Error', 'Complete'

Observer Interface
--j---a--v--a---r----x----|

onNext(V v);

onError(Throwable t);

onComplete();

Transformations
--j---a--v--a---r----x----|

A stream or RxJava Observable can be transformed using fluent API

map(s -> nextChar)

--k---b--w--b---s----x----|
Combinators
--1------3------2---------|

Two or more streams can be combined into a consolidated observable.

------4-----3--------6----|

Observable a

Observable b

Reactive Sum

(a + b)

------5--7--6---5----8----|
Solve problems by stream transformations and combinations

Complex problems can be solved by transforming streams before an observer reads its values.

Problem Detect and emit double clicks. Any sequence of n clicks, where n >=2, differences between which are < 250ms is a double click

---x-x------xx-x------x--------x-----x-x------x-x------xx---x----x-x----|
---1-1------11-1------1--------1-----1-1------1-1------11---1----1-1----|

map(x ->1)

------1---------1------1--------1-------1--------1-------1---1------1---|
      1         1                       1        1       1          1
           1

throttle(<250ms)

------2---------3------1--------1-------2--------2-------2---1------2---|

filter(listSize >= 2)

map(listSize)

------x---------x-----------------------x--------x-------x----------x---|

Pseudo Code

Observable.from(InputStream mouseClickStream)
    .map(x -> 1)
    .throttle(250ms)
    .map(list.size())
    .filter(v >= 2)
    .subscribe(new Action1<Character>() {
        public void call(Character ch) {
            // Take action on double click
        }
    });
Iterator vs Reactive
Iterator
List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five");
Iterator<String> iterator = list.iterator();

while(iterator.hasNext()) {
   System.out.println(iterator.next());
}
RxJava
List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five");

Observable<String> observable = Observable.from(list);

observable.subscribe(new Action1<String>() {
    @Override
    public void call(String element) {
        System.out.println(element);
    }
});
RxJava
List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five");

Observable<String> observable = Observable.from(list);

observable.subscribe(new Action1<String>() {
        @Override
        public void call(String element) {
            System.out.println(element);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable t) {
            System.err.println(t);
        }
    },
    new Action() {
        @Override
        public void call() {
            System.out.println("We've finished");
        }
    }
);
Excel Rx Solution

(on console)

ConnectableObservable<String> input = from(System.in);
Observable<Double> a = varStream("a", input);
Observable<Double> b = varStream("b", input);
ReactiveSum sum = new ReactiveSum(a, b);
input.connect();

> a: doubleValue (return)

Input Observable
static ConnectableObservable<String> from(final InputStream stream) {
    return from(new BufferedReader(new InputStreamReader(stream)));
}

static ConnectableObservable<String> from(final BufferedReader reader) {
    return Observable.create(new OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            if (subscriber.isUnsubscribed()) {return;}
            try {
                String line;
                while(!subscriber.isUnsubscribed() && (line = reader.readLine()) != null) {
                    if (line == null || line.equals("exit")) {break;}
                    subscriber.onNext(line);
                }
            } catch (IOException e) {
                subscriber.onError(e);
            }
            if (!subscriber.isUnsubscribed()) {
                subscriber.onCompleted();
            }
        }
    }).publish();
}
Filtered Observables
public static Observable<Double> varStream(final String varName, Observable<String> input) {
    final Pattern pattern = Pattern.compile("\\^s*" + varName + "\\s*[:|=]\\s*(-?\\d+\\.?\\d*)$");
    return input
        .map(new Func1<String, Matcher>() {
            public Matcher call(String str) {
                return pattern.matcher(str);
            }
        })
        .filter(new Func1<Matcher, Boolean>() {
            public Boolean call(Matcher matcher) {
                return matcher.matches() && matcher.group(1) != null;
            }
        })
        .map(new Func1<Matcher, Double>() {
            public Double call(Matcher matcher) {
                return Double.parseDouble(matcher.group(1));
            }
        });
}
Reactive Sum
public static final class ReactiveSum implements Observer<Double> {
    private double sum;
    public ReactiveSum(Observable<Double> a, Observable<Double> b) {
        this.sum = 0;
        Observable.combineLatest(a, b, new Func2<Double, Double, Double>() {
            public Double call(Double a, Double b) {
                return a + b;
            }
        }).subscribe(this);
    }
    public void onCompleted() {
        System.out.println("Exiting last sum was : " + this.sum);
    }
    public void onError(Throwable e) {
        System.err.println("Got an error!");
        e.printStackTrace();
    }
    public void onNext(Double sum) {
        this.sum = sum;
        System.out.println("update : a + b = " + sum);
    }
}
Lambdas

"a pure function which can be created without belonging to any class. It can be passed around as if it was an object and executed on demand"

"java's entry into functional programming"

"implementation of functional interfaces"

Functional Interface

"Interfaces which have a single non-default abstract method"

Thread thread = new Thread(new Runnable(
    public void run(){
       System.out.println("Running my runnable");
    }
));
thread.start();
interface Mapper<V, M> {
    M map(V value);
}

public static <V, M> List<M> map(List<V> list, Mapper<V, M> mapper) {
    List<M> mapped = new ArrayList<M>(list.size());
    for (V v : list) {
        mapped.add(mapper.map(v));
    }
    return mapped;
}
List<Integer> mapped = map(numbers, new Mapper<Integer, Integer>() {
  @Override
  public Integer map(Integer value) {
      return value * value; // actual mapping
  }
});
Using anonymous objects
  List<Integer> mapped = map(numbers, value -> value * value);  
Using Lambda

Instead of passing an Object we are passing an Action

(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }

(int a, int b) -> {  return a + b; }

() -> System.out.println("Hello World");

(String s) -> { System.out.println(s); }

() -> 42

() -> { return 3.1415 };
parameters -> expression
Optional typography 

Compiler infers almost everything
  • Optional type declaration - No need to declare type of the parameter. Compiler can inference the same from value of the parameter.

  • Optional parenthesis around parameter - No need to declare a single parameter in parenthesis. For multiple parameters, parenthesis are required.

  • Optional curly braces - No need to use curly braces in expression body if body contains a single statement.

  • Optional return keyword - only when there is one statement in body

@Functional Interface annotation is optional and for compiler level check
@FunctionalInterface
public interface HornInterface {
    public void honk(int volume);
}


new HornInterface(
    public void honk(int volume) {
        System.out.print("horn at volume: " + volume);
    }
);
More about Lambda
Can be used in place of Functional Interfaces
new Thread(
    () -> System.out.print("Running my Runnable");
).start();
More about Lambda
Can be Referenced
// Functional interfaces stored in 'java.util.functions'

BiConsumer<T,U>

BiFunction<T,U,R>

Consumer<T>

Predicate<T>
Predicate<Integer> predicate1 = n -> n%2 == 0

Predicate<Integer> predicate2 = n -> n > 3

Consumer<String> consumer = str -> Sysmtem.out.print(str)
Can be passed around as parameters and return values
public class Main {
    public static void main(String [] a)  {
 
        List<integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
 
        System.out.println("Print all numbers:");
        evaluate(list, (n)->true);
 
        System.out.println("Print no numbers:");
        evaluate(list, (n)->false);
 
        System.out.println("Print even numbers:");
        evaluate(list, (n)-> n%2 == 0 );
 
        System.out.println("Print odd numbers:");
        evaluate(list, (n)-> n%2 == 1 );
 
        System.out.println("Print numbers greater than 5:");
        evaluate(list, (n)-> n > 5 );
    }
 
    public static void evaluate(List<integer> list, Predicate<integer> predicate) {
        for(Integer n: list)  {
            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
    }
}
More about Lambda
Its not just a syntax sugar. It is actually simpler for compiler to process.
Double colon operator

: :

Book::makeBook   // Static method of a class
book::read       // method of an instance
Book::new        // Constructor of a class
public class Java8Tester {
   public static void main(String args[]){
      List names = new ArrayList();
      names.add("Mr. McKey");
      names.add("Cartman");
      names.add("Randy Marsh");
      names.add("Timmy");
      names.add("Butters");

      names.forEach(System.out::println);
   }   
}
RxJava is Lambda compatible
Has its own set of Functional Interfaces
Action0         // Action with no parameters
Action1<T1>     // Action with 1 parameter
Action2<T1, T2> // Action with 2 parameters
Action9<T1..T9> // Action with 9 parameters
ActionN


Func0<R>        // 0 param
Func1<T1, R>    // 1 param
FuncN
Excel Rx Solution

(with Lambda)

ConnectableObservable<String> input = from(System.in);
Observable<Double> a = varStream("a", input);
Observable<Double> b = varStream("b", input);
reactiveSum(a, b);      // The difference
input.connect();
Filtered Observables
public static Observable<Double> varStream(final String varName, Observable<String> input) {
    final Pattern pattern = Pattern.compile("\\^s*" + varName + "\\s*[:|=]\\s*(-?\\d+\\.?\\d*)$");
    return input
        .map(pattern::matcher)
        .filter(m -> m.matches() && m.group(1) != null)
        .map(matcher -> matcher.group(1)
        .map(Double::parseDouble);
}
Reactive Sum
public static void ReactiveSum(Observable<Double> a, Observable<Double> b) {
    Observable.combineLatest(a, b, (x, y) -> x + y)
        .subscribe(
            sum -> System.out.println("update : a + b = " + sum),
            error -> e.printStackTrace(),
            () -> System.out.println(Exiting...));
}
Pure Functions
Predicate<Integer> even = (number) -> number % 2 == 0;
int i = 50;
while((i--) > 0) {
    System.out.println("Is five even? - " + even.test(5));
}
"a function whose return value is only determined by its inputs, without observable side effects"
Predicate<Integer> impureEven = (number) -> {
  System.out.println("Printing here is side effect!");
  return number % 2 == 0;
};
Side Effects: triggering events, throwing exceptions, I/O, changing shared state, etc
Immutable objects
"objects that cannot change their state"
String.substring() creates a new String
Immutable data makes a pure function truly pure
Functional Programs should be designed to work with immutable stateless data with short lifecycle
Higher Order Functions
public static <T, R> int highSum(
    Function <T, Integer> f1,
    Function <R, Integer> f2,
    T data1, R data2) {
        return f1.apply(data1) + f2.apply(data2);
}
"a function with at least one parameter of type function or a function that returns a function"
highSum(v -> v * v, v -> v * v * v, 3, 2);
Function<String, Integer> strToInt = str -> Integer.parseInt(str);

highSum(strToInt, strToInt, "3", "2");
Higher Order Functions
public static Function<String, String> greet(String greeting) {
    return (String name) -> greeting + " " + name + "!";
}
System.out.println(greet("Hello").apply("world");  
// Hello world!

System.out.println(greet("Goodbye").apply("cruel world");  
// Goodbye cruel world!

Function<String, String> howdy = greet("Howdy");

System.out.println(howdy.apply("Tim"));
// Howdy Tim!

System.out.println(howdy.apply("Sundar"));
// Howdy Sundar!
Like currying in Swift

Next

Observable Pattern

Observable, Observer, Subject

Schedulers

More on Transformations and Combinators

Introduction To Reactive Programming

By Achin Kumar

Introduction To Reactive Programming

  • 1,039