367
@JosePaumard RxJava J8 Stream Comparison: patterns performances

Java 8 Streams and Rx Java Comparison

Embed Size (px)

Citation preview

Page 1: Java 8 Streams and Rx Java Comparison

@JosePaumard

RxJavaJ8 Stream

Comparison:

patterns

performances

Page 2: Java 8 Streams and Rx Java Comparison

Why should we beinterested in the

Streams API?

Page 3: Java 8 Streams and Rx Java Comparison
Page 4: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Up to 2014: only one tool, the Collection Framework

Also 3rd party API: Common Collections, …

Page 5: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Up to 2014: only one tool, the Collection Framework

Also 3rd party API: Common Collections, …

From 2014: so many new APIs

Page 6: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Why so?

Because data processing is more and more important

Page 7: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Why so?

Because data processing is more and more important

and more and more complex!

Page 8: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Why so?

Because data processing is more and more important

and more and more complex!

bigger and bigger amount of data to process

Page 9: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Why so?

Because data processing is more and more important

and more and more complex!

bigger and bigger amount of data to process

controlled response time

Page 10: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

Why so?

Because data processing is more and more important

and more and more complex!

bigger and bigger amount of data to process

controlled response time

complex algorithms

Page 11: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

So data processing needs high level primitives

Page 12: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

So data processing needs high level primitives

Able to access data wherever it is

Page 13: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

So data processing needs high level primitives

Able to access data wherever it is

That provides map / filter / reduce functions

Page 14: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

So data processing needs high level primitives

Able to access data wherever it is

That provides map / filter / reduce functions

And efficient implementations of those!

Page 15: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

It’s all about data processing

So data processing needs high level primitives

Able to access data wherever it is

That provides map / filter / reduce functions

And efficient implementations of those!

Most probably implemented in parallel

Page 16: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Agenda

1) To present two API: the Java 8 Stream API and RxJava

• Fundamentals

• Implemented functionalities

• Patterns!

Page 17: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Agenda

1) To present two API: the Java 8 Stream API and RxJava

• Fundamentals

• Implemented functionalities

• Patterns!

2) And to compare those APIs

• From the developer point of view

• Performances!

Page 18: Java 8 Streams and Rx Java Comparison

@JosePaumard

Page 19: Java 8 Streams and Rx Java Comparison

@JosePaumard

Page 20: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Questions?#J8Stream

Page 21: Java 8 Streams and Rx Java Comparison

Java 8 Stream API

Page 22: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

What is a Java 8 Stream?

An object that connects to a source

Page 23: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

What is a Java 8 Stream?

An object that connects to a source

That does not hold any data

Page 24: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

What is a Java 8 Stream?

An object that connects to a source

That does not hold any data

That implements the map / filter / reduce pattern

Page 25: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

What is a Java 8 Stream?

An object that connects to a source

That does not hold any data

That implements the map / filter / reduce pattern

A new concept in JDK 8

Page 26: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Definition of a Stream

Two things about streams:

1) A Stream does not hold any data

2) A Stream does not modify the data it gets from the source

Page 27: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream() .map(s -> s.toUpperCase()).max(Comparator.comparing(s -> s.length())).ifPresent(s -> System.out.println(s)) ;

Page 28: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream() // creation of a new Stream object.map(s -> s.toUpperCase()).max(Comparator.comparing(s -> s.length())).ifPresent(s -> System.out.println(s)) ;

Page 29: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream().map(s -> s.toUpperCase()) // to upper case.filter(s -> s.length() < 20).max(Comparator.comparing(s -> s.length())).ifPresent(s -> System.out.println(s)) ;

Page 30: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream().map(s -> s.toUpperCase()).filter(s -> s.length() < 20) // remove strings longer than 20.max(Comparator.comparing(s -> s.length())).ifPresent(s -> System.out.println(s)) ;

Page 31: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream().map(s -> s.toUpperCase()).filter(s -> s.length() < 20).max(Comparator.comparing(s -> s.length())) // take the longest s.ifPresent(s -> System.out.println(s)) ;

Page 32: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream().map(s -> s.toUpperCase()).filter(s -> s.length() < 20).max(Comparator.comparing(s -> s.length())).ifPresent(s -> System.out.println(s)) ; // and print the result

Page 33: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

API Stream

Example

List<String> list = Arrays.asList("one", "two", "three") ;

list.stream().map(String::toUpperCase).filter(s -> s.length() < 20).max(Comparator.comparing(String::length)).ifPresent(System.out::println) ; // and print the result

Page 34: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Collectors

We can use collectors

List<Person> list = ... ;

list.stream().filter(person -> person.getAge() > 30).collect(Collectors.groupingBy(

Person::getAge, // key extractorCollectors.counting() // downstream collector

)) ;

Page 35: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Collectors

We can use collectors

List<Person> list = ... ;

Map<list.stream()

.filter(person -> person.getAge() > 30)

.collect(Collectors.groupingBy(

Person::getAge, // key extractorCollectors.counting() // downstream collector

)) ;

Page 36: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Collectors

We can use collectors

List<Person> list = ... ;

Map<Integer, list.stream()

.filter(person -> person.getAge() > 30)

.collect(Collectors.groupingBy(

Person::getAge, // key extractorCollectors.counting() // downstream collector

)) ;

Page 37: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Collectors

We can use collectors

List<Person> list = ... ;

Map<Integer, Long> map = list.stream()

.filter(person -> person.getAge() > 30)

.collect(Collectors.groupingBy(

Person::getAge, // key extractorCollectors.counting() // downstream collector

)) ;

Page 38: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Collectors

And we can go parallel!

List<Person> list = ... ;

Map<Integer, Long> map = list.stream().parallel()

.filter(person -> person.getAge() > 30)

.collect(Collectors.groupingBy(

Person::getAge, // key extractorCollectors.counting() // downstream collector

)) ;

Page 39: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sources of a Stream

Many ways of connecting a Stream to a source of data

Page 40: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sources of a Stream

First patterns to create a Stream

List<Person> people = Arrays.asList(p1, p2, p3);

Page 41: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sources of a Stream

First patterns to create a Stream

List<Person> people = Arrays.asList(p1, p2, p3);

Stream<Person> stream = people.stream();

Page 42: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sources of a Stream

First patterns to create a Stream

List<Person> people = Arrays.asList(p1, p2, p3);

Stream<Person> stream = people.stream();

Stream<Person> stream = Stream.of(p1, p2, p3);

Page 43: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

long count = letters.distinct().count();

Page 44: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

long count = letters.distinct().count();

> count = 15

Page 45: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

letters.boxed().collect(Collectors.groupingBy(

Function.identity(),Collectors.counting()

));

Page 46: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

Map<letters.boxed().collect(

Collectors.groupingBy(Function.identity(),Collectors.counting()

));

Page 47: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

Map<Integer, letters.boxed().collect(

Collectors.groupingBy(Function.identity(),Collectors.counting()

));

Page 48: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

Map<Integer, Long> map = letters.boxed().collect(

Collectors.groupingBy(Function.identity(),Collectors.counting()

));

Page 49: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream on String

String crazy = "supercalifragilisticexpialidocious";

IntStream letters = crazy.chars();

Map<Integer, Long> map = letters.boxed().collect(

Collectors.groupingBy(Function.identity(),Collectors.counting()

));

a -> 3c -> 3d -> 1e -> 2f -> 1g -> 1i -> 7l -> 3o -> 2p -> 2r -> 2s -> 3t -> 1u -> 2x -> 1

Page 50: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream built on the lines of a file

String book = "alice-in-wonderland.txt";

Stream<String> lines = Files.lines(Paths.get(book)); // autocloseable

Page 51: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

More patterns

Stream built on the lines of a file

Stream built the words of a String

String book = "alice-in-wonderland.txt";

Stream<String> lines = Files.lines(Paths.get(book)); // autocloseable

String line = "Alice was beginning to get very tired of";

Stream<String> words = Pattern.compile(" ").splitAsStream(line);

Page 52: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Flatmap

How to mix both to get all the words of a book?

Memory-efficient implementations built on lazy reading of the

source of data

Function<String, Stream<String>> splitToWords = line -> Pattern.compile(" ").splitAsStream(line);

Stream<String> lines = Files.lines(path);

Stream<String> words = lines.flatMap(splitToWords);

Page 53: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Flatmap

Analyzing the result

Stream<String> words = lines.flatMap(splitToWords);

long count = words.filter(word -> word.length() > 2)

.map(String::toLowerCase)

.distinct()

.count();

Page 54: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Flatmap

Another analysis of the result

Stream<String> words = lines.flatMap(splitToWords);

Map<Integer, Long> map = words.filter(word -> word.length() > 2)

.map(String::toLowerCase)// .distinct().collect(

Collectors.groupingBy(String::length,Collectors.counting()

));

Page 55: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Extracting the max from a Map

Yet another analysis of the result

map.entrySet().stream().sorted(

Entry.<Integer, Long>comparingByValue().reversed()).limit(3).forEach(System.out::println);

Page 56: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Connecting a Stream on a source

Connecting a Stream on a non-standard source is possible

Page 57: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Connecting a Stream on a source

Connecting a Stream on a non-standard source is possible

A Stream is built on 2 things:

- A Spliterator (comes from split and iterator)

- A ReferencePipeline (the implementation)

Page 58: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Connecting a Stream on a source

The Spliterator is meant to be overriden

public interface Spliterator<T> {

boolean tryAdvance(Consumer<? super T> action) ;

Spliterator<T> trySplit() ;

long estimateSize();

int characteristics();}

Page 59: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Connecting a Stream on a source

The Spliterator is meant to be overriden

public interface Spliterator<T> {

boolean tryAdvance(Consumer<? super T> action) ;

Spliterator<T> trySplit(); // not needed for non-parallel operations

long estimateSize(); // can return 0

int characteristics(); // returns a constant}

Page 60: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Examples of custom Spliterators

Suppose we have a Stream:

[1, 2, 3, 4, 5, …]

We want to regroup the elements:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], …]

Let us build a GroupingSpliterator to do that

Page 61: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

[1, 2, 3, 4, 5, …] -> [[1, 2, 3], [4, 5, 6], …]

public class GroupingSpliterator<E> implements Spliterator<Stream<E>> {

private final long grouping ;private final Spliterator<E> spliterator ;

// implementation}

Page 62: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

[1, 2, 3, 4, 5, …] -> [[1, 2, 3], [4, 5, 6], …]

public class GroupingSpliterator<E> implements Spliterator<Stream<E>> {

private final long grouping ;private final Spliterator<E> spliterator ;

// implementation}

GroupingSpliterator<Integer> gs = new GroupingSpliterator(spliterator, grouping);

Page 63: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Implementing estimateSize() and characteristics()

public long estimateSize() {return spliterator.estimateSize() / grouping ;

}

public int characteristics() {

return this.spliterator.characteristics();}

Page 64: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Implementing trySplit()

public Spliterator<Stream<E>> trySplit() {

Spliterator<E> spliterator = this.spliterator.trySplit() ;return new GroupingSpliterator<E>(spliterator, grouping) ;

}

Page 65: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Implementing tryAdvance()

public boolean tryAdvance(Consumer<? super Stream<E>> action) {

// should call action.accept() with the next element of the Stream

// and return true if more elements are to be consumed

return true ; // false when we are done}

Page 66: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

The structure of the resulting Stream is the following:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], …]

Each element is a Stream built on the elements of the

underlying Stream

Page 67: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Build a Stream element by element is done with a

Stream.Builder

Stream.Builder<E> builder = Stream.builder() ;

for (int i = 0 ; i < grouping ; i++) {spliterator.tryAdvance(element -> builder.add(element);

}

Stream<E> subStream = subBuilder.build(); // [1, 2, 3]

Page 68: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Are we done with the underlying Stream?

Stream.Builder<E> builder = Stream.builder() ;

for (int i = 0 ; i < grouping ; i++) {spliterator.tryAdvance(

element -> builder.add(element));

}

Stream<E> subStream = subBuilder.build(); // [1, 2, 3]

Page 69: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Are we done with the underlying Stream?

Stream.Builder<E> builder = Stream.builder() ;

for (int i = 0 ; i < grouping ; i++) {spliterator.tryAdvance( // when this call returns false

element -> builder.add(element));

}

Stream<E> subStream = subBuilder.build(); // [1, 2, 3]

Page 70: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Are we done with the underlying Stream?

Stream.Builder<E> builder = Stream.builder() ;boolean finished = false;for (int i = 0 ; i < grouping ; i++) {

if (spliterator.tryAdvance(element -> builder.add(element)))finished = true;

}

Stream<E> subStream = subBuilder.build(); // [1, 2, 3]

Page 71: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupingSpliterator

Are we done with the underlying Stream?

public boolean tryAdvance(Consumer<? super Stream<E>> action) {Stream.Builder<E> builder = Stream.builder() ;boolean finished = false;for (int i = 0 ; i < grouping ; i++) {

if (spliterator.tryAdvance(element -> builder.add(element)))finished = true;

}

Stream<E> subStream = subBuilder.build(); // [1, 2, 3]action.accept(subStream) ;return !finished ;

}

Page 72: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RollingSpliterator

What about building a Stream like this one:

[[1, 2, 3], [2, 3, 4], [3, 4, 5], …]

This time we need a ring buffer

Page 73: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RollingSpliterator

The tryAdvance() call on the underlying Stream becomes this:

bufferWriteIndex is an AtomicLong

private boolean advanceSpliterator() {return spliterator.tryAdvance(

element -> { buffer[bufferWriteIndex.get() % buffer.length] = element ; bufferWriteIndex.incrementAndGet() ;

});}

Page 74: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RollingSpliterator

Building the element streams from the ring buffer:

private Stream<E> buildSubstream() {

Stream.Builder<E> subBuilder = Stream.builder() ;for (int i = 0 ; i < grouping ; i++) {

subBuilder.add((E)buffer[(i + bufferReadIndex.get()) % buffer.length]

) ;}bufferReadIndex.incrementAndGet() ;Stream<E> subStream = subBuilder.build() ;return subStream ;

}

Page 75: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RollingSpliterator

Putting things together to build the tryAdvance() call

Page 76: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

public boolean tryAdvance(Consumer<? super Stream<E>> action) {boolean finished = false ;

if (bufferWriteIndex.get() == bufferReadIndex.get()) {for (int i = 0 ; i < grouping ; i++) {

if (!advanceSpliterator()) {finished = true ;

}}

}if (!advanceSpliterator()) {

finished = true ;}

Stream<E> subStream = buildSubstream() ;action.accept(subStream) ;return !finished ;

}

Page 77: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Spliterator on Spliterator

We saw how to build a Stream on another Stream by

rearranging its elements

What about building a Stream by merging the elements of

other Streams?

Page 78: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Spliterator on Spliterators

Let us take two Streams:

[1, 2, 3, …]

[a, b, c, …]

And build a ZippingSpliterator:

[F[1, a], F[2, b], F[3, c], …]

Page 79: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Spliterator on Spliterators

What about

estimateSize()

trySplit()

characteristics()?

They are the same as the underlying streams

Page 80: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Spliterator on Spliterators

We then need to implement tryAdvance()

Where transform is a BiFunction

public boolean tryAdvance(Consumer<? super R> action) {return spliterator1.tryAdvance(

e1 -> {spliterator2.tryAdvance(e2 -> {

action.accept(tranform.apply(e1, e2)) ;}) ;

}) ;}

Page 81: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

ZippingSpliterator

What about creating a Builder for this Spliterator?

ZippingSpliterator.Builder<String, String, String> builder = new ZippingSpliterator.Builder();

ZippingSpliterator<String,String,String> zippingSpliterator = builder.with(spliterator1).and(spliterator2).mergedBy((e1, e2) -> e1 + " - " + e2).build();

Page 82: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

ZippingSpliterator

The complete pattern:

Stream<String> stream1 = Stream.of("one", "two", "three");Stream<Integer> stream2 = Stream.of(1, 2, 3);

Spliterator<String> spliterator1 = stream1.spliterator();Spliterator<Integer> spliterator2 = stream2.spliterator();

Stream<String> zipped = StreamSupport.stream(zippingSpliterator, false);

Page 83: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

What did we do with Streams so far?

We took one stream and built a stream by regrouping its

elements in some ways

Page 84: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

What did we do with Streams so far?

We took one stream and built a stream by regrouping its

elements in some ways

We took to streams and we merged them, element by element,

using a bifunction

Page 85: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

What did we do with Streams so far?

We took one stream and built a stream by regrouping its

elements in some ways

We took to streams and we merged them, element by element,

using a bifunction

What about taking one element at a time, from different

streams?

Page 86: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The WeavingSpliterator

We have N streams, and we want to build a stream that takes:

- its 1st element from the 1st stream

- its 2nd element from the 2nd stream, etc…

Page 87: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The WeavingSpliterator

The estimateSize():

public long estimateSize() {int size = 0 ;for (Spliterator<E> spliterator : this.spliterators) {

size += spliterator.estimateSize() ;}return size ;

}

Page 88: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The WeavingSpliterator

The tryAdvance():

private AtomicInteger whichOne = new AtomicInteger();

public boolean tryAdvance(Consumer<? super E> action) {

return spliterators[whichOne.getAndIncrement() % spliterators.length]

.tryAdvance(action);}

Page 89: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

One last thing about Spliterators

The characteristics() method is in fact quite important

What does « characteristics » mean for a Spliterator?

Page 90: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

It is in fact a special word: characteristics

public interface Spliterator<T> {

public static final int ORDERED = 0x00000010;public static final int DISTINCT = 0x00000001;public static final int SORTED = 0x00000004;public static final int SIZED = 0x00000040;public static final int NONNULL = 0x00000100;public static final int IMMUTABLE = 0x00000400;public static final int CONCURRENT = 0x00001000;public static final int SUBSIZED = 0x00004000;

}

Page 91: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

The Spliterator holds a special word: characteristics

// ArrayListSpliteratorpublic int characteristics() {

return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;

}

// HashMap.KeySpliteratorpublic int characteristics() {

return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |Spliterator.DISTINCT;

}

Page 92: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

The Spliterator holds a special word: characteristics

This word is used for optimization

people.stream().sorted() // quicksort?.collect(Collectors.toList());

Page 93: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

The Spliterator holds a special word: characteristics

This word is used for optimization

people.stream().sorted() // quicksort? It depends on SORTED == 0.collect(Collectors.toList());

Page 94: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

The Spliterator holds a special word: characteristics

This word is used for optimization

SortedSet<Person> people = ...;

people.stream().sorted() // SORTED == 1, no quicksort.collect(Collectors.toList());

Page 95: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The Spliterator

The Spliterator holds a special word: characteristics

This word is used for optimization

ArrayList<Person> people = ...;

people.stream().sorted() // SORTED == 0, quicksort.collect(Collectors.toList());

Page 96: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The characteristics can change

Each Stream object in a pipeline has its own characteristics

Page 97: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The characteristics can change

Each Stream object in a pipeline has its own characteristics

Method Set to 0 Set to 1

filter() SIZED -

map() DISTINCT, SORTED -

flatMap() DISTINCT, SORTED, SIZED -

sorted() - SORTED, ORDERED

distinct() - DISTINCT

limit() SIZED -

peek() - -

unordered() ORDERED -

Page 98: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The characteristics can change

Each Stream object in a pipeline has its own characteristics

Method Set to 0 Set to 1

filter() SIZED -

map() DISTINCT, SORTED -

flatMap() DISTINCT, SORTED, SIZED -

sorted() - SORTED, ORDERED

distinct() - DISTINCT

limit() SIZED -

peek() - -

unordered() ORDERED -

Page 99: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The characteristics can change

Each Stream object in a pipeline has its own characteristics

Method Set to 0 Set to 1

filter() SIZED -

map() DISTINCT, SORTED -

flatMap() DISTINCT, SORTED, SIZED -

sorted() - SORTED, ORDERED

distinct() - DISTINCT

limit() SIZED -

peek() - -

unordered() ORDERED -

Page 100: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Back to the Spliterator itself

What did we do with the spliterator, and with the Stream built

on it?

Page 101: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

What did we do with Streams so far?

We took one stream and built a stream by regrouping its

elements in some ways

We took to streams and we merged them, element by element,

using a bifunction

We took a collection of streams and built a stream by taking

elements from them, in a given order

Page 102: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Wrap-up for the Stream API

The Java 8 Stream API is not just about implementing map /

filter / reduce or building hashmaps

We can use it to manipulate data in advanced ways:

- by deciding on what source we want to connect

- by deciding how we can consume the data from that source

Page 103: Java 8 Streams and Rx Java Comparison

Reactive StreamsRxJava

Page 104: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

Open source API, available on Github

Developed by Netflix

RxJava is the Java version of ReactiveX

.NET

Python, Kotlin, JavaScript, Scala, Ruby, Groovy, Rust

Android

https://github.com/ReactiveX/RxJava

Page 105: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

RxJava is not an alternative implementation of Java 8

Streams, nor the Collection framework

It is an implementation of the Reactor pattern

Page 106: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

The central class is the Observable class

Page 107: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

The central class is the Observable class

It’s big: ~10k lines of code

Page 108: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

The central class is the Observable class

It’s big: ~10k lines of code

It’s complex: ~100 static methods, ~150 non-static methods

Page 109: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

The central class is the Observable class

It’s big: ~10k lines of code

It’s complex: ~100 static methods, ~150 non-static methods

It’s complex: not only because there is a lot of things in it, but

also because the concepts are complex

Page 110: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

Interface Observer

used to « observe » an observable

Page 111: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava

Interface Observer

used to « observe » an observable

Interface Subscription

used to model the link between an observer and an

observable

Page 112: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Interface Observer

A simple interface

public interface Observer<T> {

public void onNext(T t);

public void onCompleted();

public void onError(Throwable e);}

Page 113: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How to subscribe

Subscribing to an observable

Observable<T> observable = ... ;

Subscription subscription = observable.subscribe(observer) ;

Page 114: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How to subscribe

Subscribing to an observable

Observable<T> observable = ... ;

Subscription subscription = observable.subscribe(observer) ;

public interface Subscription {

public void unsubscribe();

public void isUnsubscribe();}

Page 115: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How to subscribe

We can also just declare a callback

Observable<T> observable = ... ;

Observable<T> next = observable.doOnNext(System.out::println) ;

Observable<T> error = observable.doOnError(System.out::println) ;

Observable<T> each = observable.doOnEach(System.out::println) ;

Page 116: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava – agenda

Patterns to create Observables

How to merge observables together

Hot observables / backpressure

Page 117: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How to createan Observable

Page 118: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The usual ways

Observable from collections and arrays

Observable<String> obs1 = Observable.just("one", "two", "three") ;

List<String> strings = Arrays.asList("one", "two", "three") ;Observable<String> obs2 = Observable.from(strings) ;

Page 119: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The usual ways

Observable useful for tests

never(): never emits anything

Observable<String> empty = Observable.empty() ;Observable<String> never = Observable.never() ;Observable<String> error = Observable.<String>error(exception) ;

Page 120: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The usual ways

Series and time series

Observable<Long> longs = Observable.range(1L, 100L) ;

// intervalObservable<Long> timeSerie1 =

Observable.interval(1L, TimeUnit.MILLISECONDS) ; // serie of longs

// initial delay, then intervalObservable<Long> timeSerie2 =

Observable.timer(10L, 1L, TimeUnit.MILLISECONDS) ; // one 0

Page 121: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The usual ways

The using() method

public final static <T, Resource> Observable<T> using(final Func0<Resource> resourceFactory, // producerfinal Func1<Resource, Observable<T>> observableFactory, // functionfinal Action1<? super Resource> disposeAction // consumer

) { }

Page 122: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

The using() method

1) Creates a resource that will provide the elements

2) Uses this resource to create the elements

3) Applies the 3rd argument to the resource

This 3rd element is in fact there to close the resource

Page 123: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

Suppose we want to create an observable on the lines of a text

file

1) We need a BufferedReader

2) The we need to wrap the lines one by one in Observables

3) Then we need to close the BufferedReader

Page 124: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

Let us do that:

Func0<BufferedReader> resourceFactory = () -> new BufferedReader(new FileReader(new File(fileName)));

Action1<BufferedReader> disposeAction = br -> br.close();

Page 125: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

The problem is that… we need to handle exceptions

Func0<BufferedReader> resourceFactory = () -> {

try {return new BufferedReader(

new FileReader(new File(fileName)));} catch (Exception e) {

e.printStackTrace();} return null;

};

Page 126: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

How can we create one Observable by file line?

Page 127: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

How can we create one Observable by file line?

We could read the file line by line, put the lines in a Collection,

then build an Observable on that collection

Page 128: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

How can we create one Observable by file line?

We could read the file line by line, put the lines in a Collection,

then build an Observable on that collection

Page 129: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

How can we create one Observable by file line?

We could read the file line by line, put the lines in a Iterator,

then build an Observable on that iterator

Page 130: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

How can we create one Observable by file line?

We could read the file line by line, put the lines in a Iterator,

then build an Observable on that iterator

Creating an Observable from an Iterator:

Observable.from(() -> iterator);

Page 131: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Func1<BufferedReader, String> observableFactory = bufferedReader -> {Iterator<String> readerIterator = new Iterator<String>() {

private String currentLine = null;private boolean finished;

{currentLine = bufferedReader.readLine();finished = currentLine == null;

}

public boolean hasNext() {return !finished;

}

public String next() {String line = currentLine; currentLine = bufferedReader.readLine();finished = currentLine == null;return line;

}};

return Observable.from(() -> readerIterator);}

Page 132: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

The using() method

Made to build an Observable on a resource that needs to be

« closed » at the end of the generation of the stream

Page 133: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

How using() works

The using() method

Made to build an Observable on a resource that needs to be

« closed » at the end of the generation of the stream

It is not built on the auto closeable mechanism because

RxJava aims to be Java 6 compatible

Page 134: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Schedulers

Page 135: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava & executors

Some of those methods take a further argument

This Observable is executed in this scheduler

Scheduler is an interface (in fact an abstract class, to define

« default methods » in Java 7)

Schedulers should be used to create schedulers

Observable<Long> longs = Observable.range(0L, 100L, scheduler) ;

Page 136: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava & executors

It allows for the execution of Observable in specialized pools of

Threads

Some Observables are executed in special schedulers (cf

Javadoc)

Page 137: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Schedulers

Factory Schedulers

public final class Schedulers {

public static Scheduler immediate() {...} // immediate

public static Scheduler newThread() {...} // new thread

public static Scheduler trampoline() {...} // queued in the current// thread

}

Page 138: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Schedulers

Factory Schedulers

public final class Schedulers {

public static Scheduler computation() {...} // computation ES

public static Scheduler io() {...} // IO growing ES

public static Scheduler test() {...}

public static Scheduler from(Executor executor) {...}}

Page 139: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Schedulers

Schedulers can be seen as Executors

Some of them are specialized (IO, Computation)

Observers are called in the thread that runs the Observable

Page 140: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Schedulers

The Schedulers.from(executor) is useful to call observers in

certain threads

For instance:

Scheduler swingScheduler = Schedulers.from(

SwingUtilities::invokeLater);

Page 141: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 1st example

A simple example

Observable<Integer> range1To100 = Observable.range(1L, 100L) ;range1To100.subscribe(System.out::println) ;

Page 142: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 1st example

A simple example

Observable<Integer> range1To100 = Observable.range(1L, 100L) ;range1To100.subscribe(System.out::println) ;

> 1 2 3 4 ... 100

Page 143: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 2nd example

A not so simple example

Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ;timer.subscribe(System.out::println) ;

Page 144: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 2nd example

A not so simple example

Nothing is printed

Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ;timer.subscribe(System.out::println) ;

>

Page 145: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 2nd example

Let us modify this code

Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ;timer.subscribe(() -> {

System.out.println(Thread.currentThread().getName() + " " + Thread.currentThread().isDaemon()) ;

}) ;Thread.sleep(2) ;

Page 146: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 2nd example

Let us modify this code

Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ;timer.subscribe(() -> {

System.out.println(Thread.currentThread().getName() + " " + Thread.currentThread().isDaemon()) ;

}) ;Thread.sleep(2) ;

> RxComputationThreadPool-1 - true

Page 147: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

About the 1st & 2nd examples

The first example ran in the main thread

Page 148: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

About the 1st & 2nd examples

The first example ran in the main thread

The second example ran in a daemon thread, that does not

prevent the JVM from exiting. Nothing was printed out,

because it did not have the time to be executed.

Page 149: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

About the 1st & 2nd examples

The first example ran in the main thread

The second example ran in a daemon thread, that does not

prevent the JVM from exiting. Nothing was printed out,

because it did not have the time to be executed.

Observable are ran in their own schedulers (executors)

Page 150: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Merging Observables

Page 151: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Merging Observable together

RxJava provides a collection of methods to merge observables

together

Page 152: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Merging Observable together

RxJava provides a collection of methods to merge observables

together

With many different, very interesting semantics

Page 153: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Representing an Observable

RxJava uses « marble diagrams » to represent observables

Observable

Page 154: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Representing an Observable

RxJava uses « marble diagrams » to represent observables

On this example, onNext() is called 5 times

Observable

Page 155: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Representing an Observable

RxJava uses « marble diagrams » to represent observables

Here an exception has been thrown, no data will be generated

after it, the onError() method is called

Observable

Page 156: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Representing an Observable

RxJava uses « marble diagrams » to represent observables

Here the end of the Stream has been reached, the

onComplete() method is called

Observable

Page 157: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The ambiguous operator

The first operator is amb(), that stands for « ambiguous »

It takes the first Observable that produced data

©RxJava

O1

O2

result

Page 158: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The zip operator

The zip operator takes one element from each Observable and

combine them using a function

©RxJava

O1

O2

F(O1, O2)

Page 159: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The combine latest operator

The combineLatest is a non-strict zip operator, emits an item

each time an observable emits one

©RxJava

O1

O2

F(O1, O2)

Page 160: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Concat and merge

Concat: emits O1 and then O2, without mixing them,

merge stops on the emission of an error

©RxJava©RxJava

Page 161: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Observables of Observables

The methods we saw are defined on Iterables of Observables

public final static <T> Observable<T> merge(Iterable<Observable<T>> listOfSequences) { }

Page 162: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Observables of Observables

The methods we saw are defined on Iterables of Observables

They are also defined on Observables of Observables

public final static <T> Observable<T> merge(Iterable<Observable<T>> listOfSequences) { }

public final static <T> Observable<T> merge(Observable<Observable<T>> sequenceOfSequences) { }

Page 163: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Observables of Observables

And the marble diagrams are different

public final static <T> Observable<T> merge(Iterable<Observable<T>> listOfSequences) { }

©RxJava

Page 164: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Observables of Observables

And the marble diagrams are different

public final static <T> Observable<T> merge(Observable<Observable<T>> sequenceOfSequences) { }

©RxJava

Page 165: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Observables of Observables

Then comes the switchOnNext operator

public final static <T> Observable<T> switchOnNext(Observable<Observable<T>> sequenceOfSequences) { }

©RxJava

Page 166: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Hot and cold Observables

Page 167: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

A cold Observable emits items if it is observered

Page 168: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

A cold Observable emits items if it is observered

A hot Observable emits items when it is created

Page 169: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Let us see an example

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

Page 170: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Let us see an example

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

> 0 - one 1 - one 2 – one ...

Page 171: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Let us see an example

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Thread.sleep(5500);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

Page 172: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Let us see an example

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Thread.sleep(5500);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

> 0 - one 1 - one 2 – one ...

Page 173: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

It means that the timer does not increment itself if not

observed

This Observable is cold

Page 174: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

It means that the timer does not increment itself if not

observed

This Observable is cold

How can we make it hot?

Page 175: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Making it hot:

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

Observable<String> moreManyStrings = Observable.combineLatest(

timer, Observable.just("two"),(i, s) -> i + " - " + s).forEach(System.out::println);

Page 176: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

It prints out the following:

> 0 - one 0 - two1 – one1 - two2 – one2 – two ...

Page 177: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

Making it hot:Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);

Observable<String> manyStrings = Observable.combineLatest(

timer, Observable.just("one"),(i, s) -> i + " - " + s).forEach(System.out::println);

Thread.sleep(5500);

Observable<String> moreManyStrings = Observable.combineLatest(

timer, Observable.just("two"),(i, s) -> i + " - " + s).forEach(System.out::println);

Page 178: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A 3rd example

It then prints out the following!

> 0 - one1 - one2 - one3 - one4 - one5 - one5 - two6 - one6 - two7 - one7 – two ...

Page 179: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

So in its first use, timer is a cold Observable

And in the second one, it becomes a hot Observable

If used more than once, a cold Observable will be seen hot by

the 2nd and later observers

Page 180: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

Problem: what happens if we have many observers to

subscribe?

Page 181: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

Problem: what happens if we have many observers to

subscribe?

Our application could miss the first values emitted by an

observable

How can we fix that?

Page 182: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

We can use the cache method

cache(int capacity) { }

O1

O2

Page 183: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

A cached timer

Creating a cached timer:

Observable<Long> timer = Observable.interval(1, TimeUnit.SECONDS);Observable<Long> cachedTimer = timer.cache(1_000);

...

Page 184: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

ConnectableObservable

We can do better and use a ConnectableObservable

(which is an Observable)

// does not count as a subscriptionConnectableObservable<Long> publish = observable.publish();

// take the time to connect all the observers

// then call publish.connect();

Page 185: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Cold and hot Observable

In fact the Observable returned by the connect() call is itself a

hot Observable

So this is also a way to create a hot Observable

Page 186: Java 8 Streams and Rx Java Comparison

Coffe break?

Page 187: Java 8 Streams and Rx Java Comparison

Coffe break!Map, filter, reduce, collect

Repeating & retrying

Dealing with time

Backpressure

Combining Java 8 Streams

& RxJava

Comparisons

The future: reactive

support in Java 9

Page 188: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Map, filter,reduce and collect

Page 189: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Map and filter

Map / filter, return an Observable

Emits only the elements that match the predicate

map(Func1<T, R> mapping) { } cast(Class<R> clazz) { } // casts the elements

filter(Func1<T, Boolean> predicate) { }

Page 190: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Materializing

Materialize: special type of mapping

Emit a Notification object that wraps the item, with metadata

Useful for logging

Does the reverse:

materialize() { } // Observable<Notification<T>>

dematerialize() { } // Observable<T>

Page 191: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Selecting ranges

Selecting ranges of elements

first() { }last() { }skip(int n) { }limit(int n) { }take(int n) { }

Page 192: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Special filtering

Special functions

Emits a true then complete on the onComplete

if the Observable emitted at least one item

exists(Func1<T, Boolean> predicate) { }

Page 193: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Special filtering

Special functions

Emits the nth item then complete on the onNext

if the Observable emitted at least n items

elementAt(int n) { }

Page 194: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Special filtering

Special functions

Emits nothing then complete on the onComplete

ignoreElement() { }

Page 195: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Special filtering

Special functions

Emits the first item on the onComplete

or emits an error on the second item emitted

single() { }

Page 196: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Special filtering

Special functions

Emits the matching item if it has been seen, on onComplete

or emits an error if not, on onComplete

single(Func1<T, Boolean> predicate) { }

Page 197: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Classical reductions

all(Func1<T, Boolean> predicate) { } // Observable<Boolean>count() { } // Observable<Long>

forEach(Action1<T> consumer) { } // void

Page 198: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Accumulations

Reduce: returns the reduction of all the items, on onComplete

Returns an error if the observable is empty

reduce(Func2<T, T, T> accumulator) { } // Observable<T>

Page 199: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Accumulations

Reduce: returns the reduction of all the items, on onComplete

In case the observable might be empty, use the other version

of reduce, that takes a seed

reduce(Func2<T, T, T> accumulator) { } // Observable<T>

reduce(seed, Func2<T, T, T> accumulator) { } // Observable<T>

Page 200: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Accumulations

Scan: returns the reduction step by step, on onNext

Can also take a seed

reduce(Func2<T, T, T> accumulator) { } // Observable<T>

scan(Func2<T, T, T> accumulator) { } // Observable<T>

reduce(seed, Func2<T, T, T> accumulator) { } // Observable<T>

Page 201: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Collecting data in a mutable container

Example: adding the elements to a list

collect(Func0<R> stateFactory, // ProducerAction2<R, T> collector) { } // BiConsumer

collect(ArrayList::new, // ProducerArrayList::add) { } // BiConsumer

Page 202: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Ready to use collectors for lists:

toList() { } // Observable<List<T>>toSortedList() { } // Observable<List<T>>

Page 203: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Ready to use collectors for lists:

And for maps (toMap can lose items):

toList() { } // Observable<List<T>>toSortedList() { } // Observable<List<T>>

toMultimap(Func1<T, K> keySelector, // Observable<Func1<T, V> valueSelector) { } // Map<K, Collection<T>>

toMap(Func1<T, K> keySelector) { } // Observable<Map<K, T>>

Page 204: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

A special kind of map:

The returned observable could hold a single map,

but it does not

groupBy(Func1<T, K> keySelector) { } // function

Page 205: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

A special kind of map:

The returned observable could hold a single map,

but it does not

It holds GroupedObservable items, which is an Observable

with a key

groupBy(Func1<T, K> keySelector) { } // function

Page 206: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

A special kind of map:

The returned observable could hold a single map,

but it does not

Instead of returning an Iterable of key / value pairs

It returns an Observable of key / value pairs

groupBy(Func1<T, K> keySelector) { } // function

Page 207: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Let us see an example

Observable<Person> people = ...;

// Observable<GroupedObservable<Integer, Person>>people.groupBy(Person::getAge)

Page 208: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Let us see an example

Observable<Person> people = ...;

// Observable<GroupedObservable<Integer, Person>>people.groupBy(Person::getAge)

.filter(groupedObs -> groupedObs.getKey() > 20)

Page 209: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Let us see an example

Observable<Person> people = ...;

// GroupedObservable<Integer, Person> extends Observable<Person>people.groupBy(Person::getAge)

.filter(groupedObs -> groupedObs.getKey() > 20)

.flatMap(groupedObs -> groupedObs)

Page 210: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reductions & collections

Let us see an example

Observable<Person> people = ...;

// Observable<Integer>people.groupBy(Person::getAge)

.filter(groupedObs -> groupedObs.getKey() > 20)

.flatMap(groupedObs -> groupedObs)

.count();

Page 211: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Wrap-up on map / filter / reduce

All those methods return an Observable

The result is thus wrapped in an Observable

Chaining operations is made with flatMap()

Wrapping and unwrapping has a cost…

Page 212: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating and Retrying

Page 213: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The repeat method repeats the same Observable

repeat() { } // Observable<T>repeat(long times) { } // Observable<T>

Page 214: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The repeat method repeats the same Observable

repeat() { } // Observable<T>repeat(long times) { } // Observable<T>

repeatWhen(Func1<Observable<Void>>, Observable<?>> notificationHandler

) { }

Page 215: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

repeat: will repeat the same Observable again and again

repeatWhen:

- on the onComplete of the source Observable, the

notification handler is passed an Observable

- if the notification handler calls the onError or onComplete of

this passed Observable, then repeatWhen calls the same on

the returned Observable

Page 216: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

repeat: will repeat the same Observable again and again

On the returned Observable, one can invoke:

onNext(), that triggers the repetition

onComplete() or onError(), which will trigger the same call on

the source Observable

Page 217: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

This function takes an Observable<Void>

And returns an Observable<?>

Page 218: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

This function takes an Observable<Void>

And returns an Observable<?>

When the Observable to be repeated calls onComplete

Then the passed Observable calls onNext with null

As a response the returned Observable should call:

- onNext to repeat

- onComplete to stop repeating

Page 219: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The first thing we need is an Observable on which we can emit

items on demand

Page 220: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The first thing we need is an Observable on which we can emit

items on demand

For that, we need to implement the OnSubscribe interface

final Set<Subscriber<? super Void>> subscribers = new HashSet<>();

OnSubscribe<Void> onSubscribe = new OnSubscribe<Void>() {

public void call(Subscriber<? super Void> subscriber) {subscribers.add(subscriber);

}};

Page 221: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

Then create an Observable from this onSubscribe object

final Observable<Void> returnedObservable = Observable.create(onSubscribe);

final Set<Subscriber<? super Void>> subscribers = new HashSet<>();

OnSubscribe<Void> onSubscribe = new OnSubscribe<Void>() {

public void call(Subscriber<? super Void> subscriber) {subscribers.add(subscriber);

}};

Page 222: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

Then create the notification handler

Func1 notificationHandler = new Func1<Observable<Void>, Observable<Void>>() {

final Observable<Void> returnedObservable = ...;

public Observable<Void> call(Observable<Void> observable) {

// implementation}

return returnedObservable;};

Page 223: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

Then create the notification handler

observable.subscribe(new Observer<Void>() {

private int count = 0;

public void onCompleted() {}

public void onError(Throwable e) {subscribers.forEach(sub -> sub.onError(e));

}

Page 224: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

Then create the notification handler

int count = 0;

public void onNext(Void t) {if (count == 3) {

subscribers.forEach(sub -> sub.onCompleted()); // stops} else {

count++;Thread.sleep(1_000);subscribers.forEach(sub -> sub.onNext(null)); // repeat

}}

Page 225: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The complete pattern

Observable<Long> timer = Observable.interval(1, TimeUnit.MILLISECONDS).take(5);

timer.repeatWhen((Func1<? super Observable<? extends Void>, ? extends Observable<?>>)notificationHandler)

.forEach(System.out::println);

Thread.sleep(5_000);

Page 226: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

The retry method will reset the Observable on error

The retryThen() function works in the same way as for the

repeat

retry() { } // Observable<T>retry(long times) { } // Observable<T>

retryWhen(Func1<Observable<Throwable>>, Observable<?>> notificationHandler

) { }

Page 227: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Repeating & retrying

There is also a retry family of methods, that works on onError

instead of onComplete

Page 228: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Joining

Joins to Observable, based on the overlapping of durations

join(Observable<TRight> right, Func1<T, Observable<TLeftDuration>> leftDurationSelector,Func1<TRight, Observable<TRightDuration>> rightDurationSelector,Func2<T, TRight, R> resultSelector) { }

Page 229: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Join

Joins to Observable, based on the overlapping of durations

©RxJava

Left obs.

Right obs.

F(O1, O2)

Page 230: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupJoin

Joins to Observable, based on the overlapping of durations

groupJoin(Observable<T2> right, Func1<T, Observable<D1>> leftDuration,Func1<T2, Observable<D2>> rightDuration,Func2<T, <T2>, R> resultSelector)

{ }

Page 231: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

GroupJoin

Joins to Observable, based on the overlapping of durations

©RxJava

Left obs.

Right obs.

F(O1, O2)

Page 232: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Dealing with time

Page 233: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Dealing with the time

RxJava has a set of methods to deal with time

Let us go back on our cold / hot Observables

It is easy to imagine a hot Observable that emits an onNext

event each second, thus playing the role of a clock

Page 234: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sampling

With hot observables, RxJava can synchronize on a clock

sample(long period, TimeUnit timeUnit) { }

©RxJava

Page 235: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Sampling

Or synchronize on a reference Observable!

sample(Observable<U> sampler) { } // samples on emission & completion

©RxJava

O1

sampler

Page 236: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

RxJava and synchronization

A very powerful feature:

RxJava can synchronize on a clock (real-time)

And on another Observable, it can then take its own time scale

Page 237: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Measuring time

If we can measure time, then we can emit it

Will emit an the amount of time between the two last onNext

events

timeInterval() { } // Observable<TimeInterval<T>>

Page 238: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Measuring time

If we can measure time, then we can delay an emission

Will reemit the items, with a delay

This delay can be computed from the items themselves

delay(long delay, TimeUnit timeUnit) ; // Observable<T>

delay(Func1<T, Observable<U> func1) ; // Observable<T>

Page 239: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Measuring time

If we can measure time, then we can timeout

Will emit an error if no item is seen during this time

timeout(long n, TimeUnit timeUnit) { }

Page 240: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

Page 241: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Fast hot observables

What happens if a hot Observable emits too many items?

What happens when an Observer cannot keep up the pace of

an Observable?

Page 242: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Fast hot observables

What happens if a hot Observable emits too many items?

What happens when an Observer cannot keep up the pace of

an Observable?

This leads to the notion of backpressure

Page 243: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Backpressure is a way to slow down the emission of elements

It can act on the observing side

Several strategies:

- Buffering items

- Skipping items (sampling is a way to implement this)

Page 244: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Use cases can be very different!

1) The temperature sensors example

- Suppose our application handle a group of temperature

sensors

- Each sensor sends one measure every seconds

Page 245: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Use cases can be very different!

1) The temperature sensors example

- Suppose our application handle a group of temperature

sensors

- Each sensor sends one measure every seconds

Maybe we can just keep one measure every hour!

Loosing items ≠ loosing information!

Page 246: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Use cases can be very different!

2) The YouTube example

- YouTube sends a HD video to your browser

- But my bandwidth is too low

Page 247: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Use cases can be very different!

2) The YouTube example

- YouTube sends a HD video to your browser

- But my bandwidth is too low

Instead of sending HD, YouTube will send me 720p

Page 248: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure methods

Use cases can be very different!

2) The YouTube example

- YouTube sends a HD video to your browser

- But my bandwidth is too low

Instead of sending HD, YouTube will send me 720p

Loosing items ≠ loosing information!

Page 249: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

Here we are looking at the backpressure from the observer

point of view

But it can also clog a network

Acting at the Observable level can be important too!

Page 250: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Buffering

Buffering records data in a buffer and emits it

buffer(int size) { } // Observable<List<T>>

buffer(long timeSpan, TimeUnit unit) { } // Observable<List<T>>buffer(long timeSpan, TimeUnit unit, int maxSize) { }

Page 251: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Buffering

Buffering records data in a buffer (a list) and emits it

buffer(int size) { } // Observable<List<T>>

buffer(long timeSpan, TimeUnit unit) { } // Observable<List<T>>buffer(long timeSpan, TimeUnit unit, int maxSize) { }

buffer(Observable<O> bufferOpenings, // Openings eventsFunc1<O, Observable<C>> bufferClosings) { } // Closings events

Page 252: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Windowing

Windowing acts as a buffer, but emits Observables instead of

lists of buffered items

window(int size) { } // Observable<Observable<T>>

window(long timeSpan, TimeUnit unit) { } // Observable<Observable<T>>window(long timeSpan, TimeUnit unit, int maxSize) { }

window(Observable<O> bufferOpenings, // Openings eventsFunc1<O, Observable<C>> bufferClosings) { } // Closings events

Page 253: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Buffering & windowing

©RxJava

©RxJava

Page 254: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Throttling

Throttling is a sampler on the beginning or the end of a window

throttleFirst(long windowDuration, TimeUnit unit) { } // Observable<T>

throttleLast(long windowDuration, TimeUnit unit) { }

throttleWithTimeout(long windowDuration, TimeUnit unit) { }

Page 255: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Throttling

throttleFirst: emits the first item in a window of time

throttleLast: emits the last item from that window, on the next

tick of the clock

Page 256: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Throttling

Throttling is a sampler on the beginning or the end of a window

©RxJava

Page 257: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Debouncing

Debounce also limits the rate of the emission of the items, by

adding a delay before reemitting

debounce(long delay, TimeUnit timeUnit) ; // Observable<T>

debounce(Func1<T, Observable<U> func1) ; // Observable<T>

Page 258: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Debouncing

It two items are emitted within the same time frame, the first

one is lost

©RxJava

Page 259: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Wrap-up on RxJava

Complex API, many different concepts, many methods

Allows to process data in chosen threads, this is useful for IO,

computations, specialized threads (GUI threads)

Allows the synchronization of operations

on clocks

on application events

Works in pull mode, and also in push mode

backpressure

Page 260: Java 8 Streams and Rx Java Comparison

Getting the best of both worlds?

Page 261: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

What about connecting a J8 Stream to a Rx Observable?

Page 262: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

If we have an Iterator, this is easy:

Iterator<T> iterator = ... ;

Observable<T> observable = Observable.from(() -> iterator) ;

Page 263: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

If we have an Iterator, this is easy:

If we have a Spliterator, not much more complex:

Iterator<T> iterator = ... ;

Observable<T> observable = Observable.from(() -> iterator) ;

Spliterator<T> spliterator = ... ;

Observable<T> observable = Observable.from(() -> Spliterators.iterator(spliterator)) ;

Page 264: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

So if we have a Stream, we can easily build an Observable

Page 265: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

So if we have a Stream, we can easily build an Observable

What about the other way?

Page 266: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

So if we have a Stream, we can easily build an Observable

What about the other way?

1) We can build an Iterator on an Observable

2) Then build a Spliterator on an Iterator

Page 267: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API?

So if we have a Stream, we can easily build an Observable

What about the other way?

1) We can build an Iterator on an Observable

2) Then build a Spliterator on an Iterator

But we need to do that ourselves…

Page 268: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

To implement an Iterator:

1) We need to implement next() and hasNext()

2) remove() is a default method in Java 8

Page 269: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

The trick is that

an iterator pulls the date from a source

an observable pushes the data to callbacks

Page 270: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

The trick is that

an iterator pulls the date from a source

an observable pushes the data to callbacks

So we need an adapter…

Page 271: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

How has it been done in the JDK?

public static<T> Iterator<T> iterator(Spliterator<? extends T> spliterator) {

class Adapter implements Iterator<T>, Consumer<T> {// implementation

}

return new Adapter() ;}

Page 272: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

class Adapter implements Iterator<T>, Consumer<T> {boolean valueReady = false ;T nextElement;

public void accept(T t) {valueReady = true ;nextElement = t ;

}

public boolean hasNext() {if (!valueReady)

spliterator.tryAdvance(this) ; // calls accept()return valueReady ;

}

public T next() {if (!valueReady && !hasNext())

throw new NoSuchElementException() ;else {

valueReady = false ;return nextElement ;

}}

}

Page 273: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

Let us adapt this pattern!

public static<T> Iterator<T> of(Observable<? extends T> observable) {

class Adapter implements Iterator<T>, Consumer<T> {// implementation

}

return new Adapter() ;}

Page 274: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

class Adapter implements Iterator<T>, Consumer<T> {boolean valueReady = false ;T nextElement;

public void accept(T t) { // needs to get the data from the ObservablevalueReady = true ;nextElement = t ;

}

public boolean hasNext() {return valueReady ;

}

public T next() {if (!valueReady && !hasNext())

throw new NoSuchElementException() ;else {

valueReady = false ;return nextElement ;

}}

}

Page 275: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

The accept method

class Adapter implements Iterator<T>, Consumer<T> {boolean valueReady = false ;T nextElement;

public void accept(T t) {observable.subscribe(

element -> nextElement = element, // onNextexception -> valueReady = false, // onError() -> valueReady = false // onComplete

) ;}

}

Page 276: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

The accept method

class Adapter implements Iterator<T>, Consumer<T> {boolean valueReady = false ;T nextElement;

public void accept(T t) {observable.subscribe(

element -> nextElement = element, // onNextexception -> valueReady = false, // onError() -> valueReady = false // onComplete

) ;}

}

final…

Page 277: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

We can wrap those value in Atomic variable

class Adapter implements Iterator<T>, Consumer<T> {AtomicBoolean valueReady = new AtomicBoolean(false) ;AtomicReference<T> nextElement = new AtomicReference() ;

public void accept(T t) {observable.subscribe(

element -> nextElement.set(element), // onNextexception -> valueReady.set(false), // onError() -> valueReady.set(false) // onComplete

) ;}

}

Page 278: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

Cant we do better?

interface Wrapper<E> {

E get() ;

}

Wrapper<Boolean> wb = () -> true ;

Page 279: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

Cant we do better?

interface Wrapper<E> {

E get() ;

}

Wrapper<Boolean> wb = () -> true ;Action1<Boolean> onNext = b -> wb.set(b) ; // should return Wrapper<T>

Page 280: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

Cant we do better?

interface Wrapper<E> {

E get() ;

public default Wrapper<E> set(E e) {// should return a wrapper of e

}}

Wrapper<Boolean> wb = () -> true ;Action1<Boolean> onNext = b -> wb.set(b) ; // should return Wrapper<T>

Page 281: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

Cant we do better?

interface Wrapper<E> {

E get() ;

public default Wrapper<E> set(E e) {return () -> e ;

}}

Wrapper<Boolean> wb = () -> true ;Action1<Boolean> onNext = b -> wb.set(b) ; // should return Wrapper<T>

Page 282: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

We can wrap those value in Atomic variable

class Adapter implements Iterator<T>, Consumer<T> {Wrapper<Boolean> valueReady = () -> false ;Wrapper<T> nextElement ;

public void accept(T t) {observable.subscribe(

element -> nextElement.set(element), // onNextexception -> valueReady.set(false), // onError() -> valueReady.set(false) // onComplete

) ;}

}

Page 283: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Iterating on an Observable

So we can build an Iterator on an Observable

And with it, a Spliterator on an Observable

it will work on cold observables

Page 284: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Getting the best of both API

The cold observables can be implemeted with Java 8 Streams

The hot observables can be implemented by combining both

API

Page 285: Java 8 Streams and Rx Java Comparison

Comparisons:Patterns &

Performances

Page 286: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Let us do some comparisons

Let us take one use case

Implemented in Rx and J8 Streams

See the different ways of writing the same processings

And compare the processing times using JMH

Page 287: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Shakespeare plays Scrabble

Published in Java Magazine

Presented in Devoxx 2014

Used during Virtual Technology Summit

https://community.oracle.com/docs/DOC-916777

https://github.com/JosePaumard/jdk8-lambda-tour

Page 288: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Shakespeare plays Scrabble

Basically, we have the set of the words used by Shakespeare

The official Scrabble player dictionnary

And the question is: how good at Scrabble Shakespeare would

have been?

Page 289: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Shakespeare plays Scrabble

1) Build the histogram of the letters of a word

2) Number of blanks needed for a letter in a word

3) Number of blanks needed to write a word

4) Predicate to check is a word can be written with 2 blanks

5) Bonus for a doubled letter

6) Final score of a word

7) Histogram of the scores

8) Best word

Page 290: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

1) Histogram of the letters

Java 8 Stream API – Rx Java

// Histogram of the letters in a given wordFunction<String, Map<Integer, Long>> histoOfLetters =

word -> word.chars().boxed().collect(

Collectors.groupingBy(Function.identity(),Collectors.counting()

)) ;

Page 291: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

1) Histogram of the letters

Java 8 Stream API – Rx Java

// Histogram of the letters in a given wordFunc1<String, Observable<HashMap<Integer, LongWrapper>>> histoOfLetters =

word -> toIntegerObservable.call(word).collect(

() -> new HashMap<Integer, LongWrapper>(), (HashMap<Integer, LongWrapper> map, Integer value) -> {

LongWrapper newValue = map.get(value) ;if (newValue == null) {

newValue = () -> 0L ;}map.put(value, newValue.incAndSet()) ;

}) ;

Page 292: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

1) Histogram of the letters

Java 8 Stream API – Rx Javainterface LongWrapper {

long get() ;

public default LongWrapper set(long l) {return () -> l ;

}

public default LongWrapper incAndSet() {return () -> get() + 1L ;

}

public default LongWrapper add(LongWrapper other) {return () -> get() + other.get() ;

}}

Page 293: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

2) # of blanks for a letter

Java 8 Stream API – Rx Java

// number of blanks for a given letterToLongFunction<Map.Entry<Integer, Long>> blank =

entry -> Long.max(

0L, entry.getValue() -

scrabbleAvailableLetters[entry.getKey() - 'a']) ;

Page 294: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

2) # of blanks for a letter

Java 8 Stream API – Rx Java

// number of blanks for a given letterFunc1<Entry<Integer, LongWrapper>, Observable<Long>> blank =

entry ->Observable.just(

Long.max(0L, entry.getValue().get() -

scrabbleAvailableLetters[entry.getKey() - 'a']

Page 295: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

3) # of blanks for a word

Java 8 Stream API – Rx Java

// number of blanks for a given wordFunction<String, Long> nBlanks =

word -> histoOfLetters.apply(word).entrySet().stream().mapToLong(blank).sum();

Page 296: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

3) # of blanks for a word

Java 8 Stream API – Rx Java

// number of blanks for a given wordFunc1<String, Observable<Long>> nBlanks =

word -> histoOfLetters.call(word).flatMap(map -> Observable.from(() ->

map.entrySet().iterator())).flatMap(blank).reduce(Long::sum) ;

Page 297: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

4) Predicate for 2 blanks

Java 8 Stream API – Rx Java

// can a word be written with 2 blanks?Predicate<String> checkBlanks = word -> nBlanks.apply(word) <= 2 ;

// can a word be written with 2 blanks?Func1<String, Observable<Boolean>> checkBlanks =

word -> nBlanks.call(word).flatMap(l -> Observable.just(l <= 2L)) ;

Page 298: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

5) Bonus for a doubled letter – 1

Java 8 Stream API – Rx Java

// Placing the word on the board// Building the streams of first and last lettersFunction<String, IntStream> first3 =

word -> word.chars().limit(3);

Page 299: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

5) Bonus for a doubled letter – 1

Java 8 Stream API – Rx Java

// Placing the word on the board// Building the streams of first and last lettersFunc1<String, Observable<Integer>> first3 =

word -> Observable.from(

IterableSpliterator.of(word.chars().boxed().limit(3).spliterator()

)) ;

Page 300: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

5) Bonus for a doubled letter – 2

Java 8 Stream API – Rx Java

// Bonus for double letterToIntFunction<String> bonusForDoubleLetter =

word -> Stream.of(first3.apply(word), last3.apply(word)).flatMapToInt(Function.identity()).map(scoreOfALetter).max().orElse(0) ;

Page 301: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

5) Bonus for a doubled letter – 2

Java 8 Stream API – Rx Java

// Bonus for double letterFunc1<String, Observable<Integer>> bonusForDoubleLetter =

word -> Observable.just(first3.call(word), last3.call(word)).flatMap(observable -> observable).flatMap(scoreOfALetter).reduce(Integer::max) ;

Page 302: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

6) Final score of a word

Java 8 Stream API – Rx Java

// score of the word put on the boardFunction<String, Integer> score3 =

word -> 2*(score2.apply(word) + bonusForDoubleLetter.applyAsInt(word))+ (word.length() == 7 ? 50 : 0);

Page 303: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

6) Final score of a word

Java 8 Stream API – Rx Java

// score of the word put on the boardFunc1<String, Observable<Integer>> score3 =

word ->Observable.just(

score2.call(word), score2.call(word), bonusForDoubleLetter.call(word), bonusForDoubleLetter.call(word), Observable.just(word.length() == 7 ? 50 : 0)

).flatMap(observable -> observable).reduce(Integer::sum) ;

Page 304: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

7) Histogram of the scores

Java 8 Stream API – Rx Java

Function<Function<String, Integer>, Map<Integer, List<String>>>buildHistoOnScore =

score -> shakespeareWords.stream().parallel().filter(scrabbleWords::contains).filter(checkBlanks).collect(

Collectors.groupingBy(score, () -> new TreeMap<>(Comparator.reverseOrder()), Collectors.toList()

)) ;

Page 305: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

7) Histogram of the scores

Java 8 Stream API – Rx JavaFunc1<Func1<String, Observable<Integer>>, Observable<TreeMap<Integer, List<String>>>> buildHistoOnScore =

score -> Observable.from(() -> shakespeareWords.iterator()).filter(scrabbleWords::contains).filter(word -> checkBlanks.call(word).toBlocking().first()).collect(

() -> new TreeMap<Integer, List<String>>(Comparator.reverseOrder()),

(TreeMap<Integer, List<String>> map, String word) -> {Integer key = score.call(word).toBlocking().first() ;List<String> list = map.get(key) ;if (list == null) {

list = new ArrayList<String>() ;map.put(key, list) ;

}list.add(word) ;

}) ;

Page 306: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

8) Best word

Java 8 Stream API – Rx Java

// best key / value pairsList<Entry<Integer, List<String>>> finalList =

buildHistoOnScore.apply(score3).entrySet().stream().limit(3).collect(Collectors.toList()) ;

Page 307: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

8) Best word

Java 8 Stream API – Rx Java

// best key / value pairsList<Entry<Integer, List<String>>> finalList2 =

buildHistoOnScore.call(score3).flatMap(map -> Observable.from(() ->

map.entrySet().iterator())).take(3).collect(

() -> new ArrayList<Entry<Integer, List<String>>>(), (list, entry) -> { list.add(entry) ; }

).toBlocking().first() ;

Page 308: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

8) Best word

Java 8 Stream API – Rx Java// best key / value pairsCountDownLatch latch = new CountDownLatch(3) ;List<Entry<Integer, List<String>>> finalList2 =

buildHistoOnScore.call(score3).flatMap(map -> Observable.from(() ->

map.entrySet().iterator())).take(3).collect(

() -> new ArrayList<Entry<Integer, List<String>>>(), (list, entry) -> { list.add(entry) ; latch.countDown() ; }

).forEach(...) ;

latch.await() ;

Page 309: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Patterns comparison

Java 8 Stream API: clean, simple, factory methods for

Collectors

RxJava: flatMap calls, lack of factory methods

Java 8 can easily go parallel, which is a plus

Page 310: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

Let us use JMH

Standard tool for measuring code performance on the JVM

Developed as an Open JDK tool

By Aleksey Shipilev http://shipilev.net/

https://twitter.com/shipilev

http://openjdk.java.net/projects/code-tools/jmh/

http://openjdk.java.net/projects/code-tools/jcstress/

https://www.parleys.com/tutorial/java-microbenchmark-harness-the-lesser-two-evils

Page 311: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

JMH

Easy to setup

<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>1.11.1</version>

</dependency>

Page 312: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

JMH

Easy to use

@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.MILLISECONDS)@Warmup(iterations=5)@Measurement(iterations=5)@Fork(3)public List<Entry<Integer, List<String>>> measureAverage() {

// implementation to test}

Page 313: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

JMH

Launching a benchmark

> mvn clean install> java –jar target/benchmark.jar

Page 314: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

JMH

3 ways of measuring performances

average execution time

number of executions per second

quantiles diagrams

Page 315: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

Average execution time

Benchmark Mode Cnt Score Error UnitsNonParallelStreams avgt 100 29,027 ± 0,279 ms/op

Page 316: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

Average execution time

Benchmark Mode Cnt Score Error UnitsNonParallelStreams avgt 100 29,027 ± 0,279 ms/opRxJava avgt 100 253,788 ± 1,421 ms/op

Page 317: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

Average execution time

Benchmark Mode Cnt Score Error UnitsNonParallelStreams avgt 100 29,027 ± 0,279 ms/opRxJava avgt 100 253,788 ± 1,421 ms/opParallelStreams avgt 100 7,624 ± 0,055 ms/op

Page 318: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

Average execution time

RxJava spends a lot of time openning observables, due to the

all flatMap patterns

Benchmark Mode Cnt Score Error UnitsNonParallelStreams avgt 100 29,027 ± 0,279 ms/opRxJava avgt 100 253,788 ± 1,421 ms/opParallelStreams avgt 100 7,624 ± 0,055 ms/op

Page 319: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Performances

The bench is on Github:

https://github.com/JosePaumard/jdk8-stream-rx-comparison

Page 320: Java 8 Streams and Rx Java Comparison

What about Java 9?

Page 321: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

Back to the definitions:

1) A Stream does not hold any data

2) A Stream does not modify its data

Page 322: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

Back to the definitions:

1) A Stream does not hold any data

2) A Stream does not modify its data

How does a Stream work?

1) It connects to a source of data: one source = one stream

2) It consumes the data from the source: « pull mode »

Page 323: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

What about:

- Connecting several streams to a single source?

Page 324: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

What about:

- Connecting several streams to a single source?

- Connecting several sources to a single stream?

Page 325: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

What about:

- Connecting several streams to a single source?

- Connecting several sources to a single stream?

- Having a source that produces data whether or not a stream

is connected to it

Page 326: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Java 8 Stream API

What about:

- Connecting several streams to a single source?

- Connecting several sources to a single stream?

- Having a source that produces data whether or not a stream

is connected to it

Clearly, the Stream API has not been made to handle this

Page 327: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reactive Stream API

This leads to the « reactive stream » API

3rd party API: Rx Java (and several other languages)

Implementations available as a preview of JDK 9

Everything takes place in java.util.concurrent.FlowAvailable in the current JDK 9

Page 328: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Let us write a model for the source of data

public interface Publisher<T> {

public ... subscribe(Subscriber<T> subscriber);}

Page 329: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Let us write a model for the source of data

As a subscriber I will want to unsubscribe

So I need an object from the publisher

on which I can call cancel()

public interface Publisher<T> {

public ... subscribe(Subscriber<T> subscriber);}

Page 330: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Let us write a model for the source of data

The first idea that could come to mind is to return a

Subscription object

public interface Publisher<T> {

public Subscription subscribe(Subscriber<T> subscriber);}

Page 331: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Let us write a model for the source of data

But it will be a callback, to stay in an asynchronous world

public interface Publisher<T> {

public void subscribe(Subscriber<T> subscriber);}

Page 332: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);}

Page 333: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);}

public interface Subscription {

public void cancel();}

Page 334: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

The publisher might look like this

public class SimplePublisher<T> implements Publisher<T> {

private Set<Subscriber<T>> subs = ConcurrentHashMap.newKeySet();

public void subscribe(Subscriber<T> subscriber) {

if (subs.add(subscriber)) {Subscription subscription = new SimpleSubscription();subscriber.onSubscribe(subscription);

}}

}

Page 335: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

In the subscribing code

public class SimpleSubscriber<T> implements Subscriber<T> {

private Subscription subscription;

@Overridepublic void onSubscribe(Subscription subscription) {

this.subscription = subscription;}

}

Page 336: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

In the running code

Publisher<String> publisher = ...;Subscriber<String> subscriber = ...;

publisher.subscribe(subscriber);

// some more code

subscriber.getSubscription().cancel();

Page 337: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

I also need callbacks to get the data itself

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);}

Page 338: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);

}

Page 339: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);

public void onNext(T item);

}

Page 340: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);

public void onNext(T item);

public void onComplete();

}

Page 341: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Callback in the subscriber to get a subscription

public interface Subscriber<T> {

public void onSubscribe(Subscription subscription);

public void onNext(T item);

public void onComplete();

public void onError(Throwable throwable);}

Page 342: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode stream

Having a source that produces data independantly from its

consumers implies to work in an asynchronous mode

The API is built on callbacks

Page 343: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Several streams per source

In « pull mode », it would not work, or would require the

streams to be synchronized

map Filter 1 Filter 2 Average

map Filter 1 Histogram

Data

Page 344: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Several streams per source

In « pull mode », it would not work, or would require the

streams to be synchronized

In « push mode », it does not raise any problem

map Filter 1 Filter 2 Average

map Filter 1 Histogram

Data

Page 345: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Several sources for a stream

In « pull mode », it requires a special Spliterator

map Filter 1 Filter 2 Average

Data 1

Data 2

Page 346: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Several sources for a stream

In « pull mode », it requires a special Spliterator

In « push mode », since both sources are not synchronized,

we may have problems

map Filter 1 Filter 2 Average

Data 1

Data 2

Page 347: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode with several sources

At some point in our data processing pipeline we want to see

both sources as one, ie merged in some way

Page 348: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode with several sources

At some point in our data processing pipeline we want to see

both sources as one, ie merged in some way

How can we merge them if one source is faster than the other?

Page 349: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Push mode with several sources

At some point in our data processing pipeline we want to see

both sources as one, ie merged in some way

How can we merge them if one source is faster than the other?

We have all the strategies defined in RxJava

Page 350: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Merging sources in push mode

1) Decide to follow one of the streams, the first one

2) Combine the two last seen items,

- everytime a new item is generated

- or synchronized on a clock, or another source

Page 351: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Merging sources in push mode

1) Decide to follow one of the streams, the first one

2) Combine the two last seen items,

- everytime a new item is generated

- or synchronized on a clock, or another source

Sampler, Debouncer, Throttler, …

Page 352: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

The question of backpressure

What will happen if a source is « too fast »?

That is, a consumer cannot process data fast enough

It leads to the same question of « backpressure »

Page 353: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

Several strategies:

1) Create a buffer

2) Synchronize on a clock, or a gate, that could be generated

by the slow observer and sample, or windows, or

debounce, or…

3) Try to slow down the source (can be done if I have the

hand on both the producer and the consumer)

Page 354: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

There is code for that in the Subscription object

The request() method is there to give information to the

producer

public interface Subscription {

public void cancel();

public void request(long n);}

Page 355: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

There is code for that in the Subscription object

The request() method is there to give information to the

producer

public void onNext(String element) {

// process the element

this.subscription.request(1L);}

Page 356: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Backpressure

Several strategies:

1) Create a buffer

2) Synchronize on a clock, or a gate, that could be generated

by the slow observer and sample, or windows, or

debounce, or…

3) Try to slow down the source (can be done if I have the

hand on both the producer and the consumer)

4) Have several observers in parallel and then merge the

results

Page 357: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reactive Streams

New concept (at least in the JDK)

New complexity, several use cases are possible

Still under work (in the JDK and in 3rd party)

Page 358: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reactive Streams links

Some references on the reactive streams:

http://www.reactive-streams.org/

http://reactivex.io/

https://github.com/reactive-streams/

http://openjdk.java.net/jeps/266

http://gee.cs.oswego.edu/dl/jsr166/dist/docs/index.html

Page 359: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Reactive Streams links

In the classes currently available in the JSR 166 package:

- The class Flow has the Publisher, Subscriber and

Subscription interfaces, and the Processor interface

- The class SubmissionPublisher, that implements Publisher,

meant to be overriden or used as a component of a complete

implementation

Just made it to the OpenJDK 9

Page 360: Java 8 Streams and Rx Java Comparison

Conclusion

Page 361: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Conclusion

Functional programming is in the mood

From the pure performance point of view, things are not that

simple

Java 8 Streams have adopted a partial functional approach,

which is probably a good trade off

Page 362: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Conclusion

Java 8 Stream API: great API to process data in a « pull »

mode

The introduction of a « push » mode allows for many

improvements (synchronization, backpressure)

The backpressure question is relevant

Loosing items ≠ loosing information!

Page 363: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Conclusion

RxJava: rich and complex API

many patterns are available in Java 8 Streams

can run in Java 7 applications

the « push » approach is very interesting

choose your use case carefully, to avoir performance hits

http://www.reactive-streams.org/

http://reactivex.io/

https://github.com/reactive-streams/

Page 364: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Conclusion

Java 8 Streams: part of the JDK

good performances, efficient memory footprint

parallelization

extensible through the Spliterator patterns

Page 365: Java 8 Streams and Rx Java Comparison

@JosePaumard#Devoxx #J8Stream

Conclusion

Streams & Reactive Streams are very active topics

Java Stream has been released with Java 8, improvements

will be added in Java 9 and beyond

Reactive Streams has several 3rd party implementations

(RxJava) in several languages

Will be part of Java 9

Page 366: Java 8 Streams and Rx Java Comparison

Thank you

Page 367: Java 8 Streams and Rx Java Comparison

Q/A