SlideShare une entreprise Scribd logo
1  sur  254
Télécharger pour lire hors ligne
@JosePaumard
RxJava
J8 Stream
Comparison:
patterns & performances
Why should we be
interested in the
Streams API?
@JosePaumard#J8Stream
It’s all about data processing
Up to 2014: only one tool, the Collection Framework
Also 3rd party API: Common Collections, …
@JosePaumard#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
@JosePaumard#J8Stream
It’s all about data processing
Why so?
Because data processing is more and more important
@JosePaumard#J8Stream
It’s all about data processing
Why so?
Because data processing is more and more important
And more and more complex!
@JosePaumard#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
@JosePaumard#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
@JosePaumard#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 algorithm
@JosePaumard#J8Stream
It’s all about data processing
So data processing needs high level primitives
@JosePaumard#J8Stream
It’s all about data processing
So data processing needs high level primitives
Able to access data wherever it is
@JosePaumard#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
@JosePaumard#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!
@JosePaumard#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
@JosePaumard#J8Stream
Agenda
1) To present two API: the Java 8 Stream API and RxJava
• Fundamentals
• Implemented functionalities
• Patterns!
@JosePaumard#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!
@JosePaumard
@JosePaumard
@JosePaumard#J8Stream
Questions?
#J8Stream
Java 8
Stream API
@JosePaumard#J8Stream
API Stream
What is a Java 8 Stream?
An object that connects to a source
@JosePaumard#J8Stream
API Stream
What is a Java 8 Stream?
An object that connects to a source
That does not hold any data
@JosePaumard#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
@JosePaumard#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
@JosePaumard#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)) ;
@JosePaumard#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)) ;
@JosePaumard#J8Stream
API Stream
Example
List<String> list = Arrays.asList("one", "two", "three") ;
list.stream()
.map(s -> s.toUpperCase()) // to upper case
.max(Comparator.comparing(s -> s.length()))
.ifPresent(s -> System.out.println(s)) ;
@JosePaumard#J8Stream
API Stream
Example
List<String> list = Arrays.asList("one", "two", "three") ;
list.stream()
.map(s -> s.toUpperCase())
.max(Comparator.comparing(s -> s.length())) // take the longest s
.ifPresent(s -> System.out.println(s)) ;
@JosePaumard#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)) ; // and print the result
@JosePaumard#J8Stream
API Stream
Example
List<String> list = Arrays.asList("one", "two", "three") ;
list.stream()
.map(String::toUpperCase)
.max(Comparator.comparing(String::length))
.ifPresent(System.out::println) ; // and print the result
@JosePaumard#J8Stream
Collectors
We can use collectors
List<Person> list = ... ;
list.stream()
.filter(person -> person.getAge() > 30)
.collect(
Collectors.groupingBy(
Person::getAge, // key extractor
Collectors.counting() // downstream collector
)
) ;
@JosePaumard#J8Stream
Collectors
We can use collectors
List<Person> list = ... ;
Map<
list.stream()
.filter(person -> person.getAge() > 30)
.collect(
Collectors.groupingBy(
Person::getAge, // key extractor
Collectors.counting() // downstream collector
)
) ;
@JosePaumard#J8Stream
Collectors
We can use collectors
List<Person> list = ... ;
Map<Integer,
list.stream()
.filter(person -> person.getAge() > 30)
.collect(
Collectors.groupingBy(
Person::getAge, // key extractor
Collectors.counting() // downstream collector
)
) ;
@JosePaumard#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 extractor
Collectors.counting() // downstream collector
)
) ;
@JosePaumard#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 extractor
Collectors.counting() // downstream collector
)
) ;
@JosePaumard#J8Stream
Sources of a Stream
Many ways of connecting a Stream to a source of data
@JosePaumard#J8Stream
Sources of a Stream
First patterns to create a Stream
List<Person> people = Arrays.asList(p1, p2, p3);
@JosePaumard#J8Stream
Sources of a Stream
First patterns to create a Stream
List<Person> people = Arrays.asList(p1, p2, p3);
Stream<Person> stream = people.stream();
@JosePaumard#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);
@JosePaumard#J8Stream
More patterns
Stream on String
String crazy = "supercalifragilisticexpialidocious";
IntStream letters = crazy.chars();
long count = letters.distinct().count();
@JosePaumard#J8Stream
More patterns
Stream on String
String crazy = "supercalifragilisticexpialidocious";
IntStream letters = crazy.chars();
long count = letters.distinct().count();
> count = 15
@JosePaumard#J8Stream
More patterns
Stream on String
String crazy = "supercalifragilisticexpialidocious";
IntStream letters = crazy.chars();
letters.boxed().collect(
Collectors.groupingBy(
Function.identity(),
Collectors.counting()
)
);
@JosePaumard#J8Stream
More patterns
Stream on String
String crazy = "supercalifragilisticexpialidocious";
IntStream letters = crazy.chars();
Map<
letters.boxed().collect(
Collectors.groupingBy(
Function.identity(),
Collectors.counting()
)
);
@JosePaumard#J8Stream
More patterns
Stream on String
String crazy = "supercalifragilisticexpialidocious";
IntStream letters = crazy.chars();
Map<Integer,
letters.boxed().collect(
Collectors.groupingBy(
Function.identity(),
Collectors.counting()
)
);
@JosePaumard#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()
)
);
@JosePaumard#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
@JosePaumard#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);
@JosePaumard#J8Stream
Flatmap
How to mix both to get all the words of a book?
Function<String, Stream<String>> splitToWords =
line -> Pattern.compile(" ").splitAsStream(line);
Stream<String> lines = Files.lines(path);
Stream<String> words = lines.flatMap(splitToWords);
@JosePaumard#J8Stream
Flatmap
Analyzing the result
Stream<String> words = lines.flatMap(splitToWords);
long count =
words.filter(word -> word.length() > 2)
.map(String::toLowerCase)
.distinct()
.count();
@JosePaumard#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()
)
);
@JosePaumard#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);
@JosePaumard#J8Stream
Connecting a Stream on a source
Connecting a Stream on a non-standard source is possible
@JosePaumard#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)
@JosePaumard#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();
}
@JosePaumard#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 processings
long estimateSize(); // can return 0
int characteristics(); // returns a constant
}
@JosePaumard#J8Stream
Examples of custom Spliterators
Suppose we have a Stream [1, 2, 3, …]
We want to regroup the elements: [[1, 2, 3], [4, 5, 6], …]
Let us build a GroupingSpliterator to do that
@JosePaumard#J8Stream
GroupingSpliterator
[1, 2, 3, 4, 5, …] -> [[1, 2, 3], [4, 5, 6], [7, 8, 9], …]
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);
@JosePaumard#J8Stream
GroupingSpliterator
Implementing estimateSize() and characteristics()
public long estimateSize() {
return spliterator.estimateSize() / grouping ;
}
public int characteristics() {
return this.spliterator.characteristics();
}
@JosePaumard#J8Stream
GroupingSpliterator
Implementing trySplit()
public Spliterator<Stream<E>> trySplit() {
Spliterator<E> spliterator = this.spliterator.trySplit() ;
return new GroupingSpliterator<E>(spliterator, grouping) ;
}
@JosePaumard#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
}
@JosePaumard#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
@JosePaumard#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]
@JosePaumard#J8Stream
GroupingSpliterator
How do we know if we are 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]
@JosePaumard#J8Stream
GroupingSpliterator
How do we know if we are 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]
@JosePaumard#J8Stream
GroupingSpliterator
How do we know if we are 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]
@JosePaumard#J8Stream
GroupingSpliterator
How do we know if we are 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 ;
}
@JosePaumard#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
@JosePaumard#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() ;
});
}
@JosePaumard#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 ;
}
@JosePaumard#J8Stream
RollingSpliterator
Putting things together to build the tryAdvance() call
@JosePaumard#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 ;
}
@JosePaumard#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?
@JosePaumard#J8Stream
Spliterator on Spliterators
Let us take two Streams:
[1, 2, 3, 4, …]
[a, b, c, d, …]
And build a ZippingSpliterator:
[F(1, a), F(2, b), F(3, c), …]
@JosePaumard#J8Stream
Spliterator on Spliterators
What about
estimateSize()
trySplit()
characteristics()?
They are the same as the underlying streams
@JosePaumard#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)) ;
}) ;
}) ;
}
@JosePaumard#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();
@JosePaumard#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);
@JosePaumard#J8Stream
What did we do with Streams so far?
We took one stream and built a stream by regrouping its
elements in some ways
@JosePaumard#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
@JosePaumard#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?
@JosePaumard#J8Stream
The WeavingSpliterator
We have N streams, and we want to build a stream that takes:
- 1st element from the 1st stream
- 2nd element from the 2nd stream, etc…
@JosePaumard#J8Stream
The WeavingSpliterator
The estimateSize():
public long estimateSize() {
int size = 0 ;
for (Spliterator<E> spliterator : this.spliterators) {
size += spliterator.estimateSize() ;
}
return size ;
}
@JosePaumard#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);
}
@JosePaumard#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
@JosePaumard#J8Stream
Wrap-up for the Stream API
The Java 8 Stream API is not just about implementing map /
filter / reduce of 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
Reactive Streams
RxJava
@JosePaumard#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
@JosePaumard#J8Stream
RxJava
RxJava is not an alternative implementation of Java 8
Streams, nor the Collection framework
It is an implementation of the Reactor pattern
@JosePaumard#J8Stream
RxJava
The central class is the Observable class
@JosePaumard#J8Stream
RxJava
The central class is the Observable class
It’s big: ~10k lines of code
@JosePaumard#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
@JosePaumard#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
@JosePaumard#J8Stream
RxJava
Interface Observer
used to « observe » an observable
@JosePaumard#J8Stream
RxJava
Interface Observer
used to « observe » an observable
Interface Subscription
used to model the link between an observer and an
observable
@JosePaumard#J8Stream
Interface Observer
A simple interface
public interface Observer<T> {
public void onNext(T t);
public void onCompleted();
public void onError(Throwable e);
}
@JosePaumard#J8Stream
How to subscribe
Subscribing to an observable
Observable<T> observable = ... ;
Subscription subscription = observable.subscribe(observer) ;
@JosePaumard#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();
}
@JosePaumard#J8Stream
RxJava – agenda
Patterns to create Observables
How to merge observables together
Hot observables / backpressure
@JosePaumard#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) ;
@JosePaumard#J8Stream
The usual ways
Observable useful for tests
Observable<String> empty = Observable.empty() ;
Observable<String> never = Observable.never() ;
Observable<String> error = Observable.<String>error(exception) ;
@JosePaumard#J8Stream
The usual ways
Series and time series
Observable<Long> longs = Observable.range(1L, 100L) ;
// interval
Observable<Long> timeSerie1 =
Observable.interval(1L, TimeUnit.MILLISECONDS) ; // a serie of longs
// initial delay, then interval
Observable<Long> timeSerie2 =
Observable.timer(10L, 1L, TimeUnit.MILLISECONDS) ; // one 0
@JosePaumard#J8Stream
The usual ways
The using() method
public final static <T, Resource> Observable<T> using(
final Func0<Resource> resourceFactory, // producer
final Func1<Resource, Observable<T>> observableFactory, // function
final Action1<? super Resource> disposeAction // consumer
) { }
@JosePaumard#J8Stream
The usual ways
The using() method
public final static <T, Resource> Observable<T> using(
final Func0<Resource> resourceFactory, // producer
final Func1<Resource, Observable<T>> observableFactory, // function
final Action1<? super Resource> disposeAction // consumer
) { }
@JosePaumard#J8Stream
How using() works
1) a resource is created using the resourceFactory
2) an observable is created from the resource using the
observableFactory
3) this observable is further decorated with actions for
exception handling
@JosePaumard#J8Stream
RxJava & executors
Some of those methods take a further argument
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) ;
@JosePaumard#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
}
@JosePaumard#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) {...}
}
@JosePaumard#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
@JosePaumard#J8Stream
Schedulers
The Schedulers.from(executor) is useful to call observers in
certain threads
For instance:
Scheduler swingScheduler =
Schedulers.from(
SwingUtilities::invokeLater
);
@JosePaumard#J8Stream
A 1st example
A simple example
Observable<Integer> range1To100 = Observable.range(1L, 100L) ;
range1To100.subscribe(System.out::println) ;
@JosePaumard#J8Stream
A 1st example
A simple example
Observable<Integer> range1To100 = Observable.range(1L, 100L) ;
range1To100.subscribe(System.out::println) ;
> 1 2 3 4 ... 100
@JosePaumard#J8Stream
A 2nd example
A not so simple example
Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ;
timer.subscribe(System.out::println) ;
@JosePaumard#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) ;
>
@JosePaumard#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) ;
@JosePaumard#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
@JosePaumard#J8Stream
About the 1st & 2nd examples
The first example ran in the main thread
@JosePaumard#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.
@JosePaumard#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)
@JosePaumard#J8Stream
Merging Observable together
RxJava provides a collection of methods to merge
observables together
@JosePaumard#J8Stream
Merging Observable together
RxJava provides a collection of methods to merge
observables together
With many different, very interesting semantics
@JosePaumard#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
@JosePaumard#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)
@JosePaumard#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)
@JosePaumard#J8Stream
Concat and merge
Concat: emits O1 and then O2, without mixing them, merge
stops on the emission of an error
©RxJava©RxJava
@JosePaumard#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) { }
@JosePaumard#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) { }
@JosePaumard#J8Stream
Observables of Observables
And the marble diagrams are different
public final static <T> Observable<T> merge(
Iterable<Observable<T>> listOfSequences) { }
©RxJava
@JosePaumard#J8Stream
Observables of Observables
And the marble diagrams are different
public final static <T> Observable<T> merge(
Observable<Observable<T>> sequenceOfSequences) { }
©RxJava
@JosePaumard#J8Stream
Observables of Observables
Then comes the switchOnNext operator
public final static <T> Observable<T> switchOnNext(
Observable<Observable<T>> sequenceOfSequences) { }
©RxJava
@JosePaumard#J8Stream
A 3rd example
A little more tricky
Observable<Integer> range = Observable.range(1, 100) ;
Observable<String> manyStrings =
Observable.combineLatest(
range, Observable.just("one"),
(integer, string) -> string) ;
@JosePaumard#J8Stream
A 3rd example
A little more tricky
Observable<Integer> range = Observable.range(1, 100) ;
Observable<String> manyStrings =
Observable.combineLatest(
range, Observable.just("one"),
(integer, string) -> string) ;
> one (and nothing more)
@JosePaumard#J8Stream
A 3rd example
A little more tricky
Observable<Integer> range = Observable.range(1, 100) ;
Observable<String> manyStrings =
Observable.combineLatest(
range, Observable.just("one"),
(integer, string) -> string) ;
> one (and nothing more)
Combines two source Observables
by emitting an item that
aggregates
the latest values of each of the
source Observables
each time an item is received from
either of the source Observables,
where this aggregation is defined
by a specified function.
@JosePaumard#J8Stream
A 4th example
Ok, so what about this one?
Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ;
Observable<String> manyStrings =
Observable.combineLatest(
timer, Observable.just("one"),
(integer, string) -> string) ;
@JosePaumard#J8Stream
A 4th example
Ok, so what about this one?
Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ;
Observable<String> manyStrings =
Observable.combineLatest(
timer, Observable.just("one"),
(integer, string) -> string) ;
> one one one one one one ...
@JosePaumard#J8Stream
A 4th example
Ok, so what about this one?
It seems that timer does not behave as range…
Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ;
Observable<String> manyStrings =
Observable.combineLatest(
timer, Observable.just("one"),
(integer, string) -> string) ;
> one one one one one one ...
@JosePaumard#J8Stream
Cold and hot observables
And indeed it does not!
@JosePaumard#J8Stream
Cold and hot observables
And indeed it does not!
Range is cold observable = produces when observed
@JosePaumard#J8Stream
Cold and hot observables
And indeed it does not!
Range is cold observable = produces when observed
Timer is a hot observable = produces, observed or not
@JosePaumard#J8Stream
Cold and hot observables
And indeed it does not!
Range is cold observable = produces when observed
Timer is a hot observable = produces, observed or not
Be careful, a cold observable can become hot
@JosePaumard#J8Stream
Cold and hot observables
An observable can have as many observers as we want
Thus, a cold observable observed by an observer will
generate values according to this observer
If another observer subscribes to it, it will see this observable
as a hot observable
@JosePaumard#J8Stream
Cold and hot observables
Problem: what happens if we have many observers to
subscribe?
@JosePaumard#J8Stream
Cold and hot observables
Problem: what happens if we have many observers to
subscribe?
Our application could miss the first values emitted by an
observable
@JosePaumard#J8Stream
Cold and hot observables
We can use the cache method
cache(int capacity) { }
@JosePaumard#J8Stream
Cold and hot observables
We can do better and use a ConnectableObservable
(which is an Observable)
// does not count as a subscription
ConnectableObservable<Long> publish = observable.publish();
// take the time to connect all the observers
// then call
publish.connect();
@JosePaumard#J8Stream
Subscribing to an Observable
About 10 different versions of doOnSomething
Each = the 3 callbacks: onNext, onError, onComplete
For instance, onNext() only acts with the onNext callback
doOnEach(Action1<T> onEach) { } // consumer
@JosePaumard#J8Stream
Subscribing to an Observable
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) { }
@JosePaumard#J8Stream
Subscribing to an Observable
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>
@JosePaumard#J8Stream
Subscribing to an Observable
Selecting ranges of elements
first() { }
last() { }
skip(int n) { }
limit(int n) { }
take(int n) { }
@JosePaumard#J8Stream
Subscribing to an Observable
Special functions
Emits a true then complete on the onComplete
if the Observable emitted at least one item
exists(Func1<T, Boolean> predicate) { }
@JosePaumard#J8Stream
Subscribing to an Observable
Special functions
Emits the nth item then complete on the onNext
if the Observable emitted at least n items
elementAt(int n) { }
@JosePaumard#J8Stream
Subscribing to an Observable
Special functions
Emits nothing then complete on the onComplete
ignoreElement() { }
@JosePaumard#J8Stream
Subscribing to an Observable
Special functions
Emits the first item on the onComplete
or emits an error on the second item emitted
single() { }
@JosePaumard#J8Stream
Subscribing to an Observable
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) { }
@JosePaumard#J8Stream
Reductions & collections
Classical reductions
all(Func1<T, Boolean> predicate) { } // Observable<Boolean>
count() { } // Observable<Long>
forEach(Action1<T> consumer) { } // void
@JosePaumard#J8Stream
Reductions & collections
Accumulations
Reduce: returns the reduction of all the items, on onComplete
Scan: returns the reduction step by step, on onNext
reduce(Func2<T, T, T> accumulator) { } // Observable<T>
scan(Func2<T, T, T> accumulator) { } // Observable<T>
@JosePaumard#J8Stream
Reductions & collections
Collecting data in a mutable container
Example: adding the elements to a list
collect(Func0<R> stateFactory, // producer
Action2<R, T> collector) { } // BiConsumer
collect(ArrayList::new, // producer
ArrayList::add) { } // BiConsumer
@JosePaumard#J8Stream
Reductions & collections
Ready to use collectors for lists:
toList() { } // Observable<List<T>>
toSortedList() { } // Observable<List<T>>
@JosePaumard#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>>
@JosePaumard#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
@JosePaumard#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 holds its key
groupBy(Func1<T, K> keySelector) { } // function
@JosePaumard#J8Stream
Repeating & retrying
The repeat method repeats the same Observable
repeat() { } // Observable<T>
repeat(long times) { } // Observable<T>
repeatWhen(
Func1<Observable<Void>>, Observable<?>> notificationHandler
) { }
@JosePaumard#J8Stream
Repeating & retrying
repeat: will repeat the same Observable again and again
On the returned Observable, one can invoke:
onComplete() or onError(), which will trigger the same call on
the source Observable
onNext(), that triggers the repetition
@JosePaumard#J8Stream
Repeating & retrying
The retry method will reset the Observable on error
retry() { } // Observable<T>
retry(long times) { } // Observable<T>
retryWhen(
Func1<Observable<Throwable>>, Observable<?>> notificationHandler
) { }
@JosePaumard#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) { }
@JosePaumard#J8Stream
Join
Joins to Observable, based on the overlapping of durations
©RxJava
Left obs.
Right obs.
F(O1, O2)
@JosePaumard#J8Stream
GroupJoin
Joins to Observable, based on the overlapping of durations
groupJoin(
Observable<T2> right,
Func1<? super T, ? extends Observable<D1>> leftDuration,
Func1<? super T2, ? extends Observable<D2>> rightDuration,
Func2<? super T, ? super Observable<T2>, ? extends R> resultSelector)
{ }
@JosePaumard#J8Stream
GroupJoin
Joins to Observable, based on the overlapping of durations
©RxJava
Left obs.
Right obs.
F(O1, O2)
@JosePaumard#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
@JosePaumard#J8Stream
Sampling
With hot observables, RxJava can synchronize on a clock
sample(long period, TimeUnit timeUnit) { }
©RxJava
@JosePaumard#J8Stream
Sampling
Or synchronize on a reference Observable!
sample(Observable<U> sampler) { } // samples on emission & completion
©RxJava
O1
sampler
@JosePaumard#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
@JosePaumard#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>>
@JosePaumard#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>
@JosePaumard#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) { }
@JosePaumard#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?
@JosePaumard#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
@JosePaumard#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)
@JosePaumard#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) { }
@JosePaumard#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 events
Func1<O, Observable<C>> bufferClosings) { } // Closings events
@JosePaumard#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 events
Func1<O, Observable<C>> bufferClosings) { } // Closings events
@JosePaumard#J8Stream
Buffering & windowing
Windowing acts as a buffer, but emits Observables instead of
lists of buffered items
@JosePaumard#J8Stream
Buffering & windowing
©RxJava
©RxJava
@JosePaumard#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) { }
@JosePaumard#J8Stream
Throttling
Throttling is a sampler on the beginning or the end of a
window
©RxJava
@JosePaumard#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>
@JosePaumard#J8Stream
Debouncing
It two items are emitted within the same time frame, the first
one is lost
©RxJava
@JosePaumard#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
Getting the best of
both worlds?
@JosePaumard#J8Stream
Getting the best of both API?
What about connecting a J8 Stream to a Rx Observable?
@JosePaumard#J8Stream
Getting the best of both API?
If we have an Iterator, this is easy:
Iterator<T> iterator = ... ;
Observable<T> observable = Observable.from(() -> iterator) ;
@JosePaumard#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)) ;
@JosePaumard#J8Stream
Getting the best of both API?
So if we have a Stream, we can easily build an Observable
@JosePaumard#J8Stream
Getting the best of both API?
So if we have a Stream, we can easily build an Observable
What about the other way?
@JosePaumard#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
@JosePaumard#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…
@JosePaumard#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
@JosePaumard#J8Stream
Iterating on an Observable
The trick is that
an iterator pulls the date from a source
an observable pushes the data to callbacks
@JosePaumard#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…
@JosePaumard#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() ;
}
@JosePaumard#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 ;
}
}
}
@JosePaumard#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> {
// implementation
}
return new Adapter() ;
}
@JosePaumard#J8Stream
class Adapter implements Iterator<T>, Consumer<T> {
boolean valueReady = false ;
T nextElement;
public void accept(T t) { // needs to be called by the Observable
valueReady = true ;
nextElement = t ;
}
public boolean hasNext() {
return valueReady ;
}
public T next() {
if (!valueReady && !hasNext())
throw new NoSuchElementException() ;
else {
valueReady = false ;
return nextElement ;
}
}
}
@JosePaumard#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, // onNext
exception -> valueReady = false, // onError
() -> valueReady = false // onComplete
) ;
}
}
@JosePaumard#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, // onNext
exception -> valueReady = false, // onError
() -> valueReady = false // onComplete
) ;
}
}
final…
@JosePaumard#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), // onNext
exception -> valueReady.set(false), // onError
() -> valueReady.set(false) // onComplete
) ;
}
}
@JosePaumard#J8Stream
Iterating on an Observable
Cant we do better?
interface Wrapper<E> {
E get() ;
}
Wrapper<Boolean> wb = () -> true ;
@JosePaumard#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>
@JosePaumard#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>
@JosePaumard#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>
@JosePaumard#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), // onNext
exception -> valueReady.set(false), // onError
() -> valueReady.set(false) // onComplete
) ;
}
}
@JosePaumard#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
@JosePaumard#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
Comparisons:
Patterns &
Performances
@JosePaumard#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
@JosePaumard#J8Stream
Shakespeare plays Scrabble
Published in Java Magazine
Presented in Java One 2014
Used during Virtual Technology Summit
https://community.oracle.com/docs/DOC-916777
https://github.com/JosePaumard/jdk8-lambda-tour
@JosePaumard#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?
@JosePaumard#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
@JosePaumard#J8Stream
1) Histogram of the letters
Java 8 Stream API – Rx Java
// Histogram of the letters in a given word
Function<String, Map<Integer, Long>> histoOfLetters =
word -> word.chars().boxed()
.collect(
Collectors.groupingBy(
Function.identity(),
Collectors.counting()
)
) ;
@JosePaumard#J8Stream
1) Histogram of the letters
Java 8 Stream API – Rx Java
// Histogram of the letters in a given word
Func1<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()) ;
}) ;
@JosePaumard#J8Stream
1) Histogram of the letters
Java 8 Stream API – Rx Java
interface 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() ;
}
}
@JosePaumard#J8Stream
2) # of blanks for a letter
Java 8 Stream API – Rx Java
// number of blanks for a given letter
ToLongFunction<Map.Entry<Integer, Long>> blank =
entry ->
Long.max(
0L,
entry.getValue() -
scrabbleAvailableLetters[entry.getKey() - 'a']
) ;
@JosePaumard#J8Stream
2) # of blanks for a letter
Java 8 Stream API – Rx Java
// number of blanks for a given letter
Func1<Entry<Integer, LongWrapper>, Observable<Long>> blank =
entry ->
Observable.just(
Long.max(
0L,
entry.getValue().get() -
scrabbleAvailableLetters[entry.getKey() - 'a']
@JosePaumard#J8Stream
3) # of blanks for a word
Java 8 Stream API – Rx Java
// number of blanks for a given word
Function<String, Long> nBlanks =
word -> histoOfLetters.apply(word)
.entrySet().stream()
.mapToLong(blank)
.sum();
@JosePaumard#J8Stream
3) # of blanks for a word
Java 8 Stream API – Rx Java
// number of blanks for a given word
Func1<String, Observable<Long>> nBlanks =
word -> histoOfLetters.call(word)
.flatMap(map -> Observable.from(() ->
map.entrySet().iterator()))
.flatMap(blank)
.reduce(Long::sum) ;
@JosePaumard#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)) ;
@JosePaumard#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 letters
Function<String, IntStream> first3 =
word -> word.chars().limit(3);
@JosePaumard#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 letters
Func1<String, Observable<Integer>> first3 =
word ->
Observable.from(
IterableSpliterator.of(
word.chars().boxed().limit(3).spliterator()
)
) ;
@JosePaumard#J8Stream
5) Bonus for a doubled letter – 2
Java 8 Stream API – Rx Java
// Bonus for double letter
ToIntFunction<String> bonusForDoubleLetter =
word -> Stream.of(first3.apply(word), last3.apply(word))
.flatMapToInt(Function.identity())
.map(scoreOfALetter)
.max()
.orElse(0) ;
@JosePaumard#J8Stream
5) Bonus for a doubled letter – 2
Java 8 Stream API – Rx Java
// Bonus for double letter
Func1<String, Observable<Integer>> bonusForDoubleLetter =
word -> Observable.just(first3.call(word), last3.call(word))
.flatMap(observable -> observable)
.flatMap(scoreOfALetter)
.reduce(Integer::max) ;
@JosePaumard#J8Stream
6) Final score of a word
Java 8 Stream API – Rx Java
// score of the word put on the board
Function<String, Integer> score3 =
word ->
2*(score2.apply(word)
+ bonusForDoubleLetter.applyAsInt(word))
+ (word.length() == 7 ? 50 : 0);
@JosePaumard#J8Stream
6) Final score of a word
Java 8 Stream API – Rx Java
// score of the word put on the board
Func1<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) ;
@JosePaumard#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()
)
) ;
@JosePaumard#J8Stream
7) Histogram of the scores
Java 8 Stream API – Rx Java
Func1<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) ;
}) ;
@JosePaumard#J8Stream
8) Best word
Java 8 Stream API – Rx Java
// best key / value pairs
List<Entry<Integer, List<String>>> finalList =
buildHistoOnScore.apply(score3).entrySet()
.stream()
.limit(3)
.collect(Collectors.toList()) ;
@JosePaumard#J8Stream
8) Best word
Java 8 Stream API – Rx Java
// best key / value pairs
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) ; }
)
.toBlocking()
.first() ;
@JosePaumard#J8Stream
8) Best word
Java 8 Stream API – Rx Java
// best key / value pairs
CountDownLatch latch = new CountDownLatch(3) ;
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() ;
@JosePaumard#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
@JosePaumard#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
@JosePaumard#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
Aleksey Shipilëv @shipilev
Чувак из ТВ-службы пришёл отключать
антенну. Оказался масс-
спектрометристом, сцепился языком с
тестем: стоят, обсуждают девайсы.
#наукоград
@JosePaumard#J8Stream
JMH
Easy to setup
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.11.1</version>
</dependency>
@JosePaumard#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
}
@JosePaumard#J8Stream
JMH
Launching a benchmark
> mvn clean install
> java –jar target/benchmark.jar
@JosePaumard#J8Stream
JMH
3 ways of measuring performances
average execution time
number of executions per second
quantiles diagrams
@JosePaumard#J8Stream
Performances
Average execution time
Benchmark Mode Cnt Score Error Units
NonParallelStreams avgt 100 29,027 ± 0,279 ms/op
@JosePaumard#J8Stream
Performances
Average execution time
Benchmark Mode Cnt Score Error Units
NonParallelStreams avgt 100 29,027 ± 0,279 ms/op
RxJava avgt 100 253,788 ± 1,421 ms/op
@JosePaumard#J8Stream
Performances
Average execution time
Benchmark Mode Cnt Score Error Units
NonParallelStreams avgt 100 29,027 ± 0,279 ms/op
RxJava avgt 100 253,788 ± 1,421 ms/op
ParallelStreams avgt 100 7,624 ± 0,055 ms/op
@JosePaumard#J8Stream
Performances
Average execution time
RxJava spends a lot of time openning observables, due to the
all flatMap patterns
Benchmark Mode Cnt Score Error Units
NonParallelStreams avgt 100 29,027 ± 0,279 ms/op
RxJava avgt 100 253,788 ± 1,421 ms/op
ParallelStreams avgt 100 7,624 ± 0,055 ms/op
Conclusion
@JosePaumard#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
@JosePaumard#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/
@JosePaumard#J8Stream
Conclusion
Java 8 Streams: part of the JDK
good performances, efficient memory footprint
parallelization
extensible through the Spliterator patterns
@JosePaumard#J8Stream
Conclusion
With more to come in Java 9
Java 9 is bringing a reactive framework as part of
java.util.concurrent
http://openjdk.java.net/jeps/266
http://gee.cs.oswego.edu/dl/jsr166/dist/docs/index.html (Class Flow)
Thank you
Q / A

Contenu connexe

Tendances

Java 8 Streams and Rx Java Comparison
Java 8 Streams and Rx Java ComparisonJava 8 Streams and Rx Java Comparison
Java 8 Streams and Rx Java ComparisonJosé Paumard
 
Linked to ArrayList: the full story
Linked to ArrayList: the full storyLinked to ArrayList: the full story
Linked to ArrayList: the full storyJosé Paumard
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of FlatteryJosé Paumard
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of FlatteryJosé Paumard
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1José Paumard
 
Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.David Gómez García
 
Asynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureAsynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureJosé Paumard
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developersJosé Paumard
 
JFokus 50 new things with java 8
JFokus 50 new things with java 8JFokus 50 new things with java 8
JFokus 50 new things with java 8José Paumard
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developersJosé Paumard
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardMario Fusco
 
Odessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and PythonOdessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and PythonMax Klymyshyn
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional ArchitectureJohn De Goes
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
 
Functional Programming in Java 8 - Lambdas and Streams
Functional Programming in Java 8 - Lambdas and StreamsFunctional Programming in Java 8 - Lambdas and Streams
Functional Programming in Java 8 - Lambdas and StreamsCodeOps Technologies LLP
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!John De Goes
 

Tendances (20)

Java 8 Streams and Rx Java Comparison
Java 8 Streams and Rx Java ComparisonJava 8 Streams and Rx Java Comparison
Java 8 Streams and Rx Java Comparison
 
Free your lambdas
Free your lambdasFree your lambdas
Free your lambdas
 
Linked to ArrayList: the full story
Linked to ArrayList: the full storyLinked to ArrayList: the full story
Linked to ArrayList: the full story
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1Lambda and Stream Master class - part 1
Lambda and Stream Master class - part 1
 
Java 8 Lambda Expressions
Java 8 Lambda ExpressionsJava 8 Lambda Expressions
Java 8 Lambda Expressions
 
Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.
 
Asynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureAsynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFuture
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developers
 
JFokus 50 new things with java 8
JFokus 50 new things with java 8JFokus 50 new things with java 8
JFokus 50 new things with java 8
 
Java SE 8 for Java EE developers
Java SE 8 for Java EE developersJava SE 8 for Java EE developers
Java SE 8 for Java EE developers
 
Java 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forwardJava 7, 8 & 9 - Moving the language forward
Java 7, 8 & 9 - Moving the language forward
 
Odessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and PythonOdessapy2013 - Graph databases and Python
Odessapy2013 - Graph databases and Python
 
Functional programming in java
Functional programming in javaFunctional programming in java
Functional programming in java
 
Orthogonal Functional Architecture
Orthogonal Functional ArchitectureOrthogonal Functional Architecture
Orthogonal Functional Architecture
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and Future
 
Functional Programming in Java 8 - Lambdas and Streams
Functional Programming in Java 8 - Lambdas and StreamsFunctional Programming in Java 8 - Lambdas and Streams
Functional Programming in Java 8 - Lambdas and Streams
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!
 

En vedette

Java 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsJava 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsNewCircle Training
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJosé Paumard
 
Ch4 Algorthmique Avancée - Analyse & complexité des Algorithmes
Ch4 Algorthmique Avancée - Analyse & complexité des AlgorithmesCh4 Algorthmique Avancée - Analyse & complexité des Algorithmes
Ch4 Algorthmique Avancée - Analyse & complexité des Algorithmeslotfibenromdhane
 
Ch3 Algorthmique Avancée - Méthodes Récursives
Ch3 Algorthmique Avancée - Méthodes RécursivesCh3 Algorthmique Avancée - Méthodes Récursives
Ch3 Algorthmique Avancée - Méthodes Récursiveslotfibenromdhane
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8Talha Ocakçı
 
Ch1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de BaseCh1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de Baselotfibenromdhane
 
Ch5 Algorthmique Avancée - Algorithme de Tri
Ch5 Algorthmique Avancée - Algorithme de TriCh5 Algorthmique Avancée - Algorithme de Tri
Ch5 Algorthmique Avancée - Algorithme de Trilotfibenromdhane
 
Ch7 algorithmes NP-Copmlétude
Ch7 algorithmes NP-CopmlétudeCh7 algorithmes NP-Copmlétude
Ch7 algorithmes NP-Copmlétudelotfibenromdhane
 
Ch2 Algorthmique Avancée - Récursivité
Ch2 Algorthmique Avancée - RécursivitéCh2 Algorthmique Avancée - Récursivité
Ch2 Algorthmique Avancée - Récursivitélotfibenromdhane
 
Database structure Structures Link list and trees and Recurison complete
Database structure Structures Link list and trees and Recurison complete  Database structure Structures Link list and trees and Recurison complete
Database structure Structures Link list and trees and Recurison complete Adnan abid
 
JDK 8, lambdas, streams, collectors - Bretagne Tour
JDK 8, lambdas, streams, collectors - Bretagne TourJDK 8, lambdas, streams, collectors - Bretagne Tour
JDK 8, lambdas, streams, collectors - Bretagne TourJosé Paumard
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8LivePerson
 
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautés
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautésAlphorm.com Formation Autodesk Revit 2018 : Les nouveautés
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautésAlphorm
 
Alphorm.com Formation Java Server Faces
Alphorm.com Formation Java Server FacesAlphorm.com Formation Java Server Faces
Alphorm.com Formation Java Server FacesAlphorm
 
Alphorm.com Formation CND 2/2: Réussir la certification
Alphorm.com Formation CND 2/2: Réussir la certificationAlphorm.com Formation CND 2/2: Réussir la certification
Alphorm.com Formation CND 2/2: Réussir la certificationAlphorm
 
Alphorm.com Java 8: les nouveautés
Alphorm.com Java 8: les nouveautésAlphorm.com Java 8: les nouveautés
Alphorm.com Java 8: les nouveautésAlphorm
 

En vedette (20)

Java 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsJava 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & Streams
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Ch4 Algorthmique Avancée - Analyse & complexité des Algorithmes
Ch4 Algorthmique Avancée - Analyse & complexité des AlgorithmesCh4 Algorthmique Avancée - Analyse & complexité des Algorithmes
Ch4 Algorthmique Avancée - Analyse & complexité des Algorithmes
 
Ch3 Algorthmique Avancée - Méthodes Récursives
Ch3 Algorthmique Avancée - Méthodes RécursivesCh3 Algorthmique Avancée - Méthodes Récursives
Ch3 Algorthmique Avancée - Méthodes Récursives
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Cats
CatsCats
Cats
 
Ch1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de BaseCh1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de Base
 
Ch5 Algorthmique Avancée - Algorithme de Tri
Ch5 Algorthmique Avancée - Algorithme de TriCh5 Algorthmique Avancée - Algorithme de Tri
Ch5 Algorthmique Avancée - Algorithme de Tri
 
Notifications
NotificationsNotifications
Notifications
 
Ch7 algorithmes NP-Copmlétude
Ch7 algorithmes NP-CopmlétudeCh7 algorithmes NP-Copmlétude
Ch7 algorithmes NP-Copmlétude
 
Ch2 Algorthmique Avancée - Récursivité
Ch2 Algorthmique Avancée - RécursivitéCh2 Algorthmique Avancée - Récursivité
Ch2 Algorthmique Avancée - Récursivité
 
Functional Programming in JAVA 8
Functional Programming in JAVA 8Functional Programming in JAVA 8
Functional Programming in JAVA 8
 
Database structure Structures Link list and trees and Recurison complete
Database structure Structures Link list and trees and Recurison complete  Database structure Structures Link list and trees and Recurison complete
Database structure Structures Link list and trees and Recurison complete
 
Functional Programming in Java
Functional Programming in JavaFunctional Programming in Java
Functional Programming in Java
 
JDK 8, lambdas, streams, collectors - Bretagne Tour
JDK 8, lambdas, streams, collectors - Bretagne TourJDK 8, lambdas, streams, collectors - Bretagne Tour
JDK 8, lambdas, streams, collectors - Bretagne Tour
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautés
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautésAlphorm.com Formation Autodesk Revit 2018 : Les nouveautés
Alphorm.com Formation Autodesk Revit 2018 : Les nouveautés
 
Alphorm.com Formation Java Server Faces
Alphorm.com Formation Java Server FacesAlphorm.com Formation Java Server Faces
Alphorm.com Formation Java Server Faces
 
Alphorm.com Formation CND 2/2: Réussir la certification
Alphorm.com Formation CND 2/2: Réussir la certificationAlphorm.com Formation CND 2/2: Réussir la certification
Alphorm.com Formation CND 2/2: Réussir la certification
 
Alphorm.com Java 8: les nouveautés
Alphorm.com Java 8: les nouveautésAlphorm.com Java 8: les nouveautés
Alphorm.com Java 8: les nouveautés
 

Similaire à Java 8 Stream API and RxJava Comparison

Beholding the giant pyramid of application development; why Ajax applications...
Beholding the giant pyramid of application development; why Ajax applications...Beholding the giant pyramid of application development; why Ajax applications...
Beholding the giant pyramid of application development; why Ajax applications...Javeline B.V.
 
Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016Spencer Fox
 
Biomart Update
Biomart UpdateBiomart Update
Biomart Updatebosc
 
Lecture 4 - Comm Lab: Web @ ITP
Lecture 4 - Comm Lab: Web @ ITPLecture 4 - Comm Lab: Web @ ITP
Lecture 4 - Comm Lab: Web @ ITPyucefmerhi
 
Querying data on the Web – client or server?
Querying data on the Web – client or server?Querying data on the Web – client or server?
Querying data on the Web – client or server?Ruben Verborgh
 
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)Ontico
 
Internet Technology and its Applications
Internet Technology and its ApplicationsInternet Technology and its Applications
Internet Technology and its Applicationsamichoksi
 
Cool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearchCool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearchclintongormley
 
Implementing Ajax In ColdFusion 7
Implementing Ajax In ColdFusion 7Implementing Ajax In ColdFusion 7
Implementing Ajax In ColdFusion 7Pranav Prakash
 
GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoMarcinStachniuk
 
NOSQL and Cassandra
NOSQL and CassandraNOSQL and Cassandra
NOSQL and Cassandrarantav
 
R, HTTP, and APIs, with a preview of TopicWatchr
R, HTTP, and APIs, with a preview of TopicWatchrR, HTTP, and APIs, with a preview of TopicWatchr
R, HTTP, and APIs, with a preview of TopicWatchrPortland R User Group
 
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)Portland R User Group
 
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018Amazon Web Services
 
The Power of RxJS in Nativescript + Angular
The Power of RxJS in Nativescript + AngularThe Power of RxJS in Nativescript + Angular
The Power of RxJS in Nativescript + AngularTracy Lee
 

Similaire à Java 8 Stream API and RxJava Comparison (20)

Beholding the giant pyramid of application development; why Ajax applications...
Beholding the giant pyramid of application development; why Ajax applications...Beholding the giant pyramid of application development; why Ajax applications...
Beholding the giant pyramid of application development; why Ajax applications...
 
Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016Introduction to R Short course Fall 2016
Introduction to R Short course Fall 2016
 
Easy R
Easy REasy R
Easy R
 
Biomart Update
Biomart UpdateBiomart Update
Biomart Update
 
Lecture 4 - Comm Lab: Web @ ITP
Lecture 4 - Comm Lab: Web @ ITPLecture 4 - Comm Lab: Web @ ITP
Lecture 4 - Comm Lab: Web @ ITP
 
Querying data on the Web – client or server?
Querying data on the Web – client or server?Querying data on the Web – client or server?
Querying data on the Web – client or server?
 
Javascript2839
Javascript2839Javascript2839
Javascript2839
 
Json
JsonJson
Json
 
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)
PostgreSQL - масштабирование в моде, Valentine Gogichashvili (Zalando SE)
 
Internet Technology and its Applications
Internet Technology and its ApplicationsInternet Technology and its Applications
Internet Technology and its Applications
 
Odp
OdpOdp
Odp
 
Cool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearchCool bonsai cool - an introduction to ElasticSearch
Cool bonsai cool - an introduction to ElasticSearch
 
Implementing Ajax In ColdFusion 7
Implementing Ajax In ColdFusion 7Implementing Ajax In ColdFusion 7
Implementing Ajax In ColdFusion 7
 
ORM JPA
ORM JPAORM JPA
ORM JPA
 
GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za mało
 
NOSQL and Cassandra
NOSQL and CassandraNOSQL and Cassandra
NOSQL and Cassandra
 
R, HTTP, and APIs, with a preview of TopicWatchr
R, HTTP, and APIs, with a preview of TopicWatchrR, HTTP, and APIs, with a preview of TopicWatchr
R, HTTP, and APIs, with a preview of TopicWatchr
 
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)
"R, HTTP, and APIs, with a preview of TopicWatchr" (15 November 2011)
 
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018
On-Ramp to Graph Databases and Amazon Neptune (DAT335) - AWS re:Invent 2018
 
The Power of RxJS in Nativescript + Angular
The Power of RxJS in Nativescript + AngularThe Power of RxJS in Nativescript + Angular
The Power of RxJS in Nativescript + Angular
 

Plus de José Paumard

Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19José Paumard
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfJosé Paumard
 
The Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingThe Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingJosé Paumard
 
Deep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKDeep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKJosé Paumard
 
Designing functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsDesigning functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsJosé Paumard
 
Designing functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternDesigning functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternJosé Paumard
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapesJosé Paumard
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!José Paumard
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowJosé Paumard
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJosé Paumard
 
JAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJosé Paumard
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses étatsJosé Paumard
 
ArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateauArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateauJosé Paumard
 
API Asynchrones en Java 8
API Asynchrones en Java 8API Asynchrones en Java 8
API Asynchrones en Java 8José Paumard
 
Les Streams sont parmi nous
Les Streams sont parmi nousLes Streams sont parmi nous
Les Streams sont parmi nousJosé Paumard
 

Plus de José Paumard (17)

Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19Loom Virtual Threads in the JDK 19
Loom Virtual Threads in the JDK 19
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdf
 
The Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern MatchingThe Future of Java: Records, Sealed Classes and Pattern Matching
The Future of Java: Records, Sealed Classes and Pattern Matching
 
Deep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UKDeep Dive Java 17 Devoxx UK
Deep Dive Java 17 Devoxx UK
 
Designing functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patternsDesigning functional and fluent API: application to some GoF patterns
Designing functional and fluent API: application to some GoF patterns
 
Designing functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor PatternDesigning functional and fluent API: example of the Visitor Pattern
Designing functional and fluent API: example of the Visitor Pattern
 
Construire son JDK en 10 étapes
Construire son JDK en 10 étapesConstruire son JDK en 10 étapes
Construire son JDK en 10 étapes
 
Java Keeps Throttling Up!
Java Keeps Throttling Up!Java Keeps Throttling Up!
Java Keeps Throttling Up!
 
Asynchronous Systems with Fn Flow
Asynchronous Systems with Fn FlowAsynchronous Systems with Fn Flow
Asynchronous Systems with Fn Flow
 
Java Full Throttle
Java Full ThrottleJava Full Throttle
Java Full Throttle
 
JAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) BridgeJAX-RS and CDI Bike the (Reactive) Bridge
JAX-RS and CDI Bike the (Reactive) Bridge
 
Streams in the wild
Streams in the wildStreams in the wild
Streams in the wild
 
JAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridgeJAX RS and CDI bike the reactive bridge
JAX RS and CDI bike the reactive bridge
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses états
 
ArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateauArrayList et LinkedList sont dans un bateau
ArrayList et LinkedList sont dans un bateau
 
API Asynchrones en Java 8
API Asynchrones en Java 8API Asynchrones en Java 8
API Asynchrones en Java 8
 
Les Streams sont parmi nous
Les Streams sont parmi nousLes Streams sont parmi nous
Les Streams sont parmi nous
 

Dernier

Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Seán Kennedy
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management systemChristalin Nelson
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxAnupkumar Sharma
 
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...JojoEDelaCruz
 
Activity 2-unit 2-update 2024. English translation
Activity 2-unit 2-update 2024. English translationActivity 2-unit 2-update 2024. English translation
Activity 2-unit 2-update 2024. English translationRosabel UA
 
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxQ4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxlancelewisportillo
 
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfVirtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfErwinPantujan2
 
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfGrade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfJemuel Francisco
 
How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17Celine George
 
Measures of Position DECILES for ungrouped data
Measures of Position DECILES for ungrouped dataMeasures of Position DECILES for ungrouped data
Measures of Position DECILES for ungrouped dataBabyAnnMotar
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Mark Reed
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4MiaBumagat1
 
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONTHEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONHumphrey A Beña
 
Presentation Activity 2. Unit 3 transv.pptx
Presentation Activity 2. Unit 3 transv.pptxPresentation Activity 2. Unit 3 transv.pptx
Presentation Activity 2. Unit 3 transv.pptxRosabel UA
 
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSGRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSJoshuaGantuangco2
 
Integumentary System SMP B. Pharm Sem I.ppt
Integumentary System SMP B. Pharm Sem I.pptIntegumentary System SMP B. Pharm Sem I.ppt
Integumentary System SMP B. Pharm Sem I.pptshraddhaparab530
 
The Contemporary World: The Globalization of World Politics
The Contemporary World: The Globalization of World PoliticsThe Contemporary World: The Globalization of World Politics
The Contemporary World: The Globalization of World PoliticsRommel Regala
 
Expanded definition: technical and operational
Expanded definition: technical and operationalExpanded definition: technical and operational
Expanded definition: technical and operationalssuser3e220a
 
Textual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSTextual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSMae Pangan
 

Dernier (20)

Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...
 
Concurrency Control in Database Management system
Concurrency Control in Database Management systemConcurrency Control in Database Management system
Concurrency Control in Database Management system
 
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptxYOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
 
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...
ENG 5 Q4 WEEk 1 DAY 1 Restate sentences heard in one’s own words. Use appropr...
 
Activity 2-unit 2-update 2024. English translation
Activity 2-unit 2-update 2024. English translationActivity 2-unit 2-update 2024. English translation
Activity 2-unit 2-update 2024. English translation
 
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptxQ4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
Q4-PPT-Music9_Lesson-1-Romantic-Opera.pptx
 
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfVirtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
 
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfGrade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
 
How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17How to Add Barcode on PDF Report in Odoo 17
How to Add Barcode on PDF Report in Odoo 17
 
Measures of Position DECILES for ungrouped data
Measures of Position DECILES for ungrouped dataMeasures of Position DECILES for ungrouped data
Measures of Position DECILES for ungrouped data
 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4
 
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONTHEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
 
Presentation Activity 2. Unit 3 transv.pptx
Presentation Activity 2. Unit 3 transv.pptxPresentation Activity 2. Unit 3 transv.pptx
Presentation Activity 2. Unit 3 transv.pptx
 
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTSGRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
GRADE 4 - SUMMATIVE TEST QUARTER 4 ALL SUBJECTS
 
Integumentary System SMP B. Pharm Sem I.ppt
Integumentary System SMP B. Pharm Sem I.pptIntegumentary System SMP B. Pharm Sem I.ppt
Integumentary System SMP B. Pharm Sem I.ppt
 
The Contemporary World: The Globalization of World Politics
The Contemporary World: The Globalization of World PoliticsThe Contemporary World: The Globalization of World Politics
The Contemporary World: The Globalization of World Politics
 
Expanded definition: technical and operational
Expanded definition: technical and operationalExpanded definition: technical and operational
Expanded definition: technical and operational
 
Textual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHSTextual Evidence in Reading and Writing of SHS
Textual Evidence in Reading and Writing of SHS
 

Java 8 Stream API and RxJava Comparison

  • 2. Why should we be interested in the Streams API?
  • 3. @JosePaumard#J8Stream It’s all about data processing Up to 2014: only one tool, the Collection Framework Also 3rd party API: Common Collections, …
  • 4. @JosePaumard#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
  • 5. @JosePaumard#J8Stream It’s all about data processing Why so? Because data processing is more and more important
  • 6. @JosePaumard#J8Stream It’s all about data processing Why so? Because data processing is more and more important And more and more complex!
  • 7. @JosePaumard#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
  • 8. @JosePaumard#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
  • 9. @JosePaumard#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 algorithm
  • 10. @JosePaumard#J8Stream It’s all about data processing So data processing needs high level primitives
  • 11. @JosePaumard#J8Stream It’s all about data processing So data processing needs high level primitives Able to access data wherever it is
  • 12. @JosePaumard#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
  • 13. @JosePaumard#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!
  • 14. @JosePaumard#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
  • 15. @JosePaumard#J8Stream Agenda 1) To present two API: the Java 8 Stream API and RxJava • Fundamentals • Implemented functionalities • Patterns!
  • 16. @JosePaumard#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!
  • 21. @JosePaumard#J8Stream API Stream What is a Java 8 Stream? An object that connects to a source
  • 22. @JosePaumard#J8Stream API Stream What is a Java 8 Stream? An object that connects to a source That does not hold any data
  • 23. @JosePaumard#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
  • 24. @JosePaumard#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
  • 25. @JosePaumard#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)) ;
  • 26. @JosePaumard#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)) ;
  • 27. @JosePaumard#J8Stream API Stream Example List<String> list = Arrays.asList("one", "two", "three") ; list.stream() .map(s -> s.toUpperCase()) // to upper case .max(Comparator.comparing(s -> s.length())) .ifPresent(s -> System.out.println(s)) ;
  • 28. @JosePaumard#J8Stream API Stream Example List<String> list = Arrays.asList("one", "two", "three") ; list.stream() .map(s -> s.toUpperCase()) .max(Comparator.comparing(s -> s.length())) // take the longest s .ifPresent(s -> System.out.println(s)) ;
  • 29. @JosePaumard#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)) ; // and print the result
  • 30. @JosePaumard#J8Stream API Stream Example List<String> list = Arrays.asList("one", "two", "three") ; list.stream() .map(String::toUpperCase) .max(Comparator.comparing(String::length)) .ifPresent(System.out::println) ; // and print the result
  • 31. @JosePaumard#J8Stream Collectors We can use collectors List<Person> list = ... ; list.stream() .filter(person -> person.getAge() > 30) .collect( Collectors.groupingBy( Person::getAge, // key extractor Collectors.counting() // downstream collector ) ) ;
  • 32. @JosePaumard#J8Stream Collectors We can use collectors List<Person> list = ... ; Map< list.stream() .filter(person -> person.getAge() > 30) .collect( Collectors.groupingBy( Person::getAge, // key extractor Collectors.counting() // downstream collector ) ) ;
  • 33. @JosePaumard#J8Stream Collectors We can use collectors List<Person> list = ... ; Map<Integer, list.stream() .filter(person -> person.getAge() > 30) .collect( Collectors.groupingBy( Person::getAge, // key extractor Collectors.counting() // downstream collector ) ) ;
  • 34. @JosePaumard#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 extractor Collectors.counting() // downstream collector ) ) ;
  • 35. @JosePaumard#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 extractor Collectors.counting() // downstream collector ) ) ;
  • 36. @JosePaumard#J8Stream Sources of a Stream Many ways of connecting a Stream to a source of data
  • 37. @JosePaumard#J8Stream Sources of a Stream First patterns to create a Stream List<Person> people = Arrays.asList(p1, p2, p3);
  • 38. @JosePaumard#J8Stream Sources of a Stream First patterns to create a Stream List<Person> people = Arrays.asList(p1, p2, p3); Stream<Person> stream = people.stream();
  • 39. @JosePaumard#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);
  • 40. @JosePaumard#J8Stream More patterns Stream on String String crazy = "supercalifragilisticexpialidocious"; IntStream letters = crazy.chars(); long count = letters.distinct().count();
  • 41. @JosePaumard#J8Stream More patterns Stream on String String crazy = "supercalifragilisticexpialidocious"; IntStream letters = crazy.chars(); long count = letters.distinct().count(); > count = 15
  • 42. @JosePaumard#J8Stream More patterns Stream on String String crazy = "supercalifragilisticexpialidocious"; IntStream letters = crazy.chars(); letters.boxed().collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) );
  • 43. @JosePaumard#J8Stream More patterns Stream on String String crazy = "supercalifragilisticexpialidocious"; IntStream letters = crazy.chars(); Map< letters.boxed().collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) );
  • 44. @JosePaumard#J8Stream More patterns Stream on String String crazy = "supercalifragilisticexpialidocious"; IntStream letters = crazy.chars(); Map<Integer, letters.boxed().collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) );
  • 45. @JosePaumard#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() ) );
  • 46. @JosePaumard#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
  • 47. @JosePaumard#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);
  • 48. @JosePaumard#J8Stream Flatmap How to mix both to get all the words of a book? Function<String, Stream<String>> splitToWords = line -> Pattern.compile(" ").splitAsStream(line); Stream<String> lines = Files.lines(path); Stream<String> words = lines.flatMap(splitToWords);
  • 49. @JosePaumard#J8Stream Flatmap Analyzing the result Stream<String> words = lines.flatMap(splitToWords); long count = words.filter(word -> word.length() > 2) .map(String::toLowerCase) .distinct() .count();
  • 50. @JosePaumard#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() ) );
  • 51. @JosePaumard#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);
  • 52. @JosePaumard#J8Stream Connecting a Stream on a source Connecting a Stream on a non-standard source is possible
  • 53. @JosePaumard#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)
  • 54. @JosePaumard#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(); }
  • 55. @JosePaumard#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 processings long estimateSize(); // can return 0 int characteristics(); // returns a constant }
  • 56. @JosePaumard#J8Stream Examples of custom Spliterators Suppose we have a Stream [1, 2, 3, …] We want to regroup the elements: [[1, 2, 3], [4, 5, 6], …] Let us build a GroupingSpliterator to do that
  • 57. @JosePaumard#J8Stream GroupingSpliterator [1, 2, 3, 4, 5, …] -> [[1, 2, 3], [4, 5, 6], [7, 8, 9], …] 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);
  • 58. @JosePaumard#J8Stream GroupingSpliterator Implementing estimateSize() and characteristics() public long estimateSize() { return spliterator.estimateSize() / grouping ; } public int characteristics() { return this.spliterator.characteristics(); }
  • 59. @JosePaumard#J8Stream GroupingSpliterator Implementing trySplit() public Spliterator<Stream<E>> trySplit() { Spliterator<E> spliterator = this.spliterator.trySplit() ; return new GroupingSpliterator<E>(spliterator, grouping) ; }
  • 60. @JosePaumard#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 }
  • 61. @JosePaumard#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
  • 62. @JosePaumard#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]
  • 63. @JosePaumard#J8Stream GroupingSpliterator How do we know if we are 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]
  • 64. @JosePaumard#J8Stream GroupingSpliterator How do we know if we are 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]
  • 65. @JosePaumard#J8Stream GroupingSpliterator How do we know if we are 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]
  • 66. @JosePaumard#J8Stream GroupingSpliterator How do we know if we are 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 ; }
  • 67. @JosePaumard#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
  • 68. @JosePaumard#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() ; }); }
  • 69. @JosePaumard#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 ; }
  • 71. @JosePaumard#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 ; }
  • 72. @JosePaumard#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?
  • 73. @JosePaumard#J8Stream Spliterator on Spliterators Let us take two Streams: [1, 2, 3, 4, …] [a, b, c, d, …] And build a ZippingSpliterator: [F(1, a), F(2, b), F(3, c), …]
  • 74. @JosePaumard#J8Stream Spliterator on Spliterators What about estimateSize() trySplit() characteristics()? They are the same as the underlying streams
  • 75. @JosePaumard#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)) ; }) ; }) ; }
  • 76. @JosePaumard#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();
  • 77. @JosePaumard#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);
  • 78. @JosePaumard#J8Stream What did we do with Streams so far? We took one stream and built a stream by regrouping its elements in some ways
  • 79. @JosePaumard#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
  • 80. @JosePaumard#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?
  • 81. @JosePaumard#J8Stream The WeavingSpliterator We have N streams, and we want to build a stream that takes: - 1st element from the 1st stream - 2nd element from the 2nd stream, etc…
  • 82. @JosePaumard#J8Stream The WeavingSpliterator The estimateSize(): public long estimateSize() { int size = 0 ; for (Spliterator<E> spliterator : this.spliterators) { size += spliterator.estimateSize() ; } return size ; }
  • 83. @JosePaumard#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); }
  • 84. @JosePaumard#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
  • 85. @JosePaumard#J8Stream Wrap-up for the Stream API The Java 8 Stream API is not just about implementing map / filter / reduce of 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
  • 87. @JosePaumard#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
  • 88. @JosePaumard#J8Stream RxJava RxJava is not an alternative implementation of Java 8 Streams, nor the Collection framework It is an implementation of the Reactor pattern
  • 90. @JosePaumard#J8Stream RxJava The central class is the Observable class It’s big: ~10k lines of code
  • 91. @JosePaumard#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
  • 92. @JosePaumard#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
  • 94. @JosePaumard#J8Stream RxJava Interface Observer used to « observe » an observable Interface Subscription used to model the link between an observer and an observable
  • 95. @JosePaumard#J8Stream Interface Observer A simple interface public interface Observer<T> { public void onNext(T t); public void onCompleted(); public void onError(Throwable e); }
  • 96. @JosePaumard#J8Stream How to subscribe Subscribing to an observable Observable<T> observable = ... ; Subscription subscription = observable.subscribe(observer) ;
  • 97. @JosePaumard#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(); }
  • 98. @JosePaumard#J8Stream RxJava – agenda Patterns to create Observables How to merge observables together Hot observables / backpressure
  • 99. @JosePaumard#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) ;
  • 100. @JosePaumard#J8Stream The usual ways Observable useful for tests Observable<String> empty = Observable.empty() ; Observable<String> never = Observable.never() ; Observable<String> error = Observable.<String>error(exception) ;
  • 101. @JosePaumard#J8Stream The usual ways Series and time series Observable<Long> longs = Observable.range(1L, 100L) ; // interval Observable<Long> timeSerie1 = Observable.interval(1L, TimeUnit.MILLISECONDS) ; // a serie of longs // initial delay, then interval Observable<Long> timeSerie2 = Observable.timer(10L, 1L, TimeUnit.MILLISECONDS) ; // one 0
  • 102. @JosePaumard#J8Stream The usual ways The using() method public final static <T, Resource> Observable<T> using( final Func0<Resource> resourceFactory, // producer final Func1<Resource, Observable<T>> observableFactory, // function final Action1<? super Resource> disposeAction // consumer ) { }
  • 103. @JosePaumard#J8Stream The usual ways The using() method public final static <T, Resource> Observable<T> using( final Func0<Resource> resourceFactory, // producer final Func1<Resource, Observable<T>> observableFactory, // function final Action1<? super Resource> disposeAction // consumer ) { }
  • 104. @JosePaumard#J8Stream How using() works 1) a resource is created using the resourceFactory 2) an observable is created from the resource using the observableFactory 3) this observable is further decorated with actions for exception handling
  • 105. @JosePaumard#J8Stream RxJava & executors Some of those methods take a further argument 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) ;
  • 106. @JosePaumard#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 }
  • 107. @JosePaumard#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) {...} }
  • 108. @JosePaumard#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
  • 109. @JosePaumard#J8Stream Schedulers The Schedulers.from(executor) is useful to call observers in certain threads For instance: Scheduler swingScheduler = Schedulers.from( SwingUtilities::invokeLater );
  • 110. @JosePaumard#J8Stream A 1st example A simple example Observable<Integer> range1To100 = Observable.range(1L, 100L) ; range1To100.subscribe(System.out::println) ;
  • 111. @JosePaumard#J8Stream A 1st example A simple example Observable<Integer> range1To100 = Observable.range(1L, 100L) ; range1To100.subscribe(System.out::println) ; > 1 2 3 4 ... 100
  • 112. @JosePaumard#J8Stream A 2nd example A not so simple example Observable<Integer> timer = Observable.timer(1, TimeUnit.SECONDS) ; timer.subscribe(System.out::println) ;
  • 113. @JosePaumard#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) ; >
  • 114. @JosePaumard#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) ;
  • 115. @JosePaumard#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
  • 116. @JosePaumard#J8Stream About the 1st & 2nd examples The first example ran in the main thread
  • 117. @JosePaumard#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.
  • 118. @JosePaumard#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)
  • 119. @JosePaumard#J8Stream Merging Observable together RxJava provides a collection of methods to merge observables together
  • 120. @JosePaumard#J8Stream Merging Observable together RxJava provides a collection of methods to merge observables together With many different, very interesting semantics
  • 121. @JosePaumard#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
  • 122. @JosePaumard#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)
  • 123. @JosePaumard#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)
  • 124. @JosePaumard#J8Stream Concat and merge Concat: emits O1 and then O2, without mixing them, merge stops on the emission of an error ©RxJava©RxJava
  • 125. @JosePaumard#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) { }
  • 126. @JosePaumard#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) { }
  • 127. @JosePaumard#J8Stream Observables of Observables And the marble diagrams are different public final static <T> Observable<T> merge( Iterable<Observable<T>> listOfSequences) { } ©RxJava
  • 128. @JosePaumard#J8Stream Observables of Observables And the marble diagrams are different public final static <T> Observable<T> merge( Observable<Observable<T>> sequenceOfSequences) { } ©RxJava
  • 129. @JosePaumard#J8Stream Observables of Observables Then comes the switchOnNext operator public final static <T> Observable<T> switchOnNext( Observable<Observable<T>> sequenceOfSequences) { } ©RxJava
  • 130. @JosePaumard#J8Stream A 3rd example A little more tricky Observable<Integer> range = Observable.range(1, 100) ; Observable<String> manyStrings = Observable.combineLatest( range, Observable.just("one"), (integer, string) -> string) ;
  • 131. @JosePaumard#J8Stream A 3rd example A little more tricky Observable<Integer> range = Observable.range(1, 100) ; Observable<String> manyStrings = Observable.combineLatest( range, Observable.just("one"), (integer, string) -> string) ; > one (and nothing more)
  • 132. @JosePaumard#J8Stream A 3rd example A little more tricky Observable<Integer> range = Observable.range(1, 100) ; Observable<String> manyStrings = Observable.combineLatest( range, Observable.just("one"), (integer, string) -> string) ; > one (and nothing more) Combines two source Observables by emitting an item that aggregates the latest values of each of the source Observables each time an item is received from either of the source Observables, where this aggregation is defined by a specified function.
  • 133. @JosePaumard#J8Stream A 4th example Ok, so what about this one? Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ; Observable<String> manyStrings = Observable.combineLatest( timer, Observable.just("one"), (integer, string) -> string) ;
  • 134. @JosePaumard#J8Stream A 4th example Ok, so what about this one? Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ; Observable<String> manyStrings = Observable.combineLatest( timer, Observable.just("one"), (integer, string) -> string) ; > one one one one one one ...
  • 135. @JosePaumard#J8Stream A 4th example Ok, so what about this one? It seems that timer does not behave as range… Observable<Integer> timer = Observable.interval(3, TimeUnit.SECONDS) ; Observable<String> manyStrings = Observable.combineLatest( timer, Observable.just("one"), (integer, string) -> string) ; > one one one one one one ...
  • 136. @JosePaumard#J8Stream Cold and hot observables And indeed it does not!
  • 137. @JosePaumard#J8Stream Cold and hot observables And indeed it does not! Range is cold observable = produces when observed
  • 138. @JosePaumard#J8Stream Cold and hot observables And indeed it does not! Range is cold observable = produces when observed Timer is a hot observable = produces, observed or not
  • 139. @JosePaumard#J8Stream Cold and hot observables And indeed it does not! Range is cold observable = produces when observed Timer is a hot observable = produces, observed or not Be careful, a cold observable can become hot
  • 140. @JosePaumard#J8Stream Cold and hot observables An observable can have as many observers as we want Thus, a cold observable observed by an observer will generate values according to this observer If another observer subscribes to it, it will see this observable as a hot observable
  • 141. @JosePaumard#J8Stream Cold and hot observables Problem: what happens if we have many observers to subscribe?
  • 142. @JosePaumard#J8Stream Cold and hot observables Problem: what happens if we have many observers to subscribe? Our application could miss the first values emitted by an observable
  • 143. @JosePaumard#J8Stream Cold and hot observables We can use the cache method cache(int capacity) { }
  • 144. @JosePaumard#J8Stream Cold and hot observables We can do better and use a ConnectableObservable (which is an Observable) // does not count as a subscription ConnectableObservable<Long> publish = observable.publish(); // take the time to connect all the observers // then call publish.connect();
  • 145. @JosePaumard#J8Stream Subscribing to an Observable About 10 different versions of doOnSomething Each = the 3 callbacks: onNext, onError, onComplete For instance, onNext() only acts with the onNext callback doOnEach(Action1<T> onEach) { } // consumer
  • 146. @JosePaumard#J8Stream Subscribing to an Observable 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) { }
  • 147. @JosePaumard#J8Stream Subscribing to an Observable 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>
  • 148. @JosePaumard#J8Stream Subscribing to an Observable Selecting ranges of elements first() { } last() { } skip(int n) { } limit(int n) { } take(int n) { }
  • 149. @JosePaumard#J8Stream Subscribing to an Observable Special functions Emits a true then complete on the onComplete if the Observable emitted at least one item exists(Func1<T, Boolean> predicate) { }
  • 150. @JosePaumard#J8Stream Subscribing to an Observable Special functions Emits the nth item then complete on the onNext if the Observable emitted at least n items elementAt(int n) { }
  • 151. @JosePaumard#J8Stream Subscribing to an Observable Special functions Emits nothing then complete on the onComplete ignoreElement() { }
  • 152. @JosePaumard#J8Stream Subscribing to an Observable Special functions Emits the first item on the onComplete or emits an error on the second item emitted single() { }
  • 153. @JosePaumard#J8Stream Subscribing to an Observable 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) { }
  • 154. @JosePaumard#J8Stream Reductions & collections Classical reductions all(Func1<T, Boolean> predicate) { } // Observable<Boolean> count() { } // Observable<Long> forEach(Action1<T> consumer) { } // void
  • 155. @JosePaumard#J8Stream Reductions & collections Accumulations Reduce: returns the reduction of all the items, on onComplete Scan: returns the reduction step by step, on onNext reduce(Func2<T, T, T> accumulator) { } // Observable<T> scan(Func2<T, T, T> accumulator) { } // Observable<T>
  • 156. @JosePaumard#J8Stream Reductions & collections Collecting data in a mutable container Example: adding the elements to a list collect(Func0<R> stateFactory, // producer Action2<R, T> collector) { } // BiConsumer collect(ArrayList::new, // producer ArrayList::add) { } // BiConsumer
  • 157. @JosePaumard#J8Stream Reductions & collections Ready to use collectors for lists: toList() { } // Observable<List<T>> toSortedList() { } // Observable<List<T>>
  • 158. @JosePaumard#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>>
  • 159. @JosePaumard#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
  • 160. @JosePaumard#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 holds its key groupBy(Func1<T, K> keySelector) { } // function
  • 161. @JosePaumard#J8Stream Repeating & retrying The repeat method repeats the same Observable repeat() { } // Observable<T> repeat(long times) { } // Observable<T> repeatWhen( Func1<Observable<Void>>, Observable<?>> notificationHandler ) { }
  • 162. @JosePaumard#J8Stream Repeating & retrying repeat: will repeat the same Observable again and again On the returned Observable, one can invoke: onComplete() or onError(), which will trigger the same call on the source Observable onNext(), that triggers the repetition
  • 163. @JosePaumard#J8Stream Repeating & retrying The retry method will reset the Observable on error retry() { } // Observable<T> retry(long times) { } // Observable<T> retryWhen( Func1<Observable<Throwable>>, Observable<?>> notificationHandler ) { }
  • 164. @JosePaumard#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) { }
  • 165. @JosePaumard#J8Stream Join Joins to Observable, based on the overlapping of durations ©RxJava Left obs. Right obs. F(O1, O2)
  • 166. @JosePaumard#J8Stream GroupJoin Joins to Observable, based on the overlapping of durations groupJoin( Observable<T2> right, Func1<? super T, ? extends Observable<D1>> leftDuration, Func1<? super T2, ? extends Observable<D2>> rightDuration, Func2<? super T, ? super Observable<T2>, ? extends R> resultSelector) { }
  • 167. @JosePaumard#J8Stream GroupJoin Joins to Observable, based on the overlapping of durations ©RxJava Left obs. Right obs. F(O1, O2)
  • 168. @JosePaumard#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
  • 169. @JosePaumard#J8Stream Sampling With hot observables, RxJava can synchronize on a clock sample(long period, TimeUnit timeUnit) { } ©RxJava
  • 170. @JosePaumard#J8Stream Sampling Or synchronize on a reference Observable! sample(Observable<U> sampler) { } // samples on emission & completion ©RxJava O1 sampler
  • 171. @JosePaumard#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
  • 172. @JosePaumard#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>>
  • 173. @JosePaumard#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>
  • 174. @JosePaumard#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) { }
  • 175. @JosePaumard#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?
  • 176. @JosePaumard#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
  • 177. @JosePaumard#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)
  • 178. @JosePaumard#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) { }
  • 179. @JosePaumard#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 events Func1<O, Observable<C>> bufferClosings) { } // Closings events
  • 180. @JosePaumard#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 events Func1<O, Observable<C>> bufferClosings) { } // Closings events
  • 181. @JosePaumard#J8Stream Buffering & windowing Windowing acts as a buffer, but emits Observables instead of lists of buffered items
  • 183. @JosePaumard#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) { }
  • 184. @JosePaumard#J8Stream Throttling Throttling is a sampler on the beginning or the end of a window ©RxJava
  • 185. @JosePaumard#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>
  • 186. @JosePaumard#J8Stream Debouncing It two items are emitted within the same time frame, the first one is lost ©RxJava
  • 187. @JosePaumard#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
  • 188. Getting the best of both worlds?
  • 189. @JosePaumard#J8Stream Getting the best of both API? What about connecting a J8 Stream to a Rx Observable?
  • 190. @JosePaumard#J8Stream Getting the best of both API? If we have an Iterator, this is easy: Iterator<T> iterator = ... ; Observable<T> observable = Observable.from(() -> iterator) ;
  • 191. @JosePaumard#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)) ;
  • 192. @JosePaumard#J8Stream Getting the best of both API? So if we have a Stream, we can easily build an Observable
  • 193. @JosePaumard#J8Stream Getting the best of both API? So if we have a Stream, we can easily build an Observable What about the other way?
  • 194. @JosePaumard#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
  • 195. @JosePaumard#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…
  • 196. @JosePaumard#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
  • 197. @JosePaumard#J8Stream Iterating on an Observable The trick is that an iterator pulls the date from a source an observable pushes the data to callbacks
  • 198. @JosePaumard#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…
  • 199. @JosePaumard#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() ; }
  • 200. @JosePaumard#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 ; } } }
  • 201. @JosePaumard#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> { // implementation } return new Adapter() ; }
  • 202. @JosePaumard#J8Stream class Adapter implements Iterator<T>, Consumer<T> { boolean valueReady = false ; T nextElement; public void accept(T t) { // needs to be called by the Observable valueReady = true ; nextElement = t ; } public boolean hasNext() { return valueReady ; } public T next() { if (!valueReady && !hasNext()) throw new NoSuchElementException() ; else { valueReady = false ; return nextElement ; } } }
  • 203. @JosePaumard#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, // onNext exception -> valueReady = false, // onError () -> valueReady = false // onComplete ) ; } }
  • 204. @JosePaumard#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, // onNext exception -> valueReady = false, // onError () -> valueReady = false // onComplete ) ; } } final…
  • 205. @JosePaumard#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), // onNext exception -> valueReady.set(false), // onError () -> valueReady.set(false) // onComplete ) ; } }
  • 206. @JosePaumard#J8Stream Iterating on an Observable Cant we do better? interface Wrapper<E> { E get() ; } Wrapper<Boolean> wb = () -> true ;
  • 207. @JosePaumard#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>
  • 208. @JosePaumard#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>
  • 209. @JosePaumard#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>
  • 210. @JosePaumard#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), // onNext exception -> valueReady.set(false), // onError () -> valueReady.set(false) // onComplete ) ; } }
  • 211. @JosePaumard#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
  • 212. @JosePaumard#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
  • 214. @JosePaumard#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
  • 215. @JosePaumard#J8Stream Shakespeare plays Scrabble Published in Java Magazine Presented in Java One 2014 Used during Virtual Technology Summit https://community.oracle.com/docs/DOC-916777 https://github.com/JosePaumard/jdk8-lambda-tour
  • 216. @JosePaumard#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?
  • 217. @JosePaumard#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
  • 218. @JosePaumard#J8Stream 1) Histogram of the letters Java 8 Stream API – Rx Java // Histogram of the letters in a given word Function<String, Map<Integer, Long>> histoOfLetters = word -> word.chars().boxed() .collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) ) ;
  • 219. @JosePaumard#J8Stream 1) Histogram of the letters Java 8 Stream API – Rx Java // Histogram of the letters in a given word Func1<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()) ; }) ;
  • 220. @JosePaumard#J8Stream 1) Histogram of the letters Java 8 Stream API – Rx Java interface 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() ; } }
  • 221. @JosePaumard#J8Stream 2) # of blanks for a letter Java 8 Stream API – Rx Java // number of blanks for a given letter ToLongFunction<Map.Entry<Integer, Long>> blank = entry -> Long.max( 0L, entry.getValue() - scrabbleAvailableLetters[entry.getKey() - 'a'] ) ;
  • 222. @JosePaumard#J8Stream 2) # of blanks for a letter Java 8 Stream API – Rx Java // number of blanks for a given letter Func1<Entry<Integer, LongWrapper>, Observable<Long>> blank = entry -> Observable.just( Long.max( 0L, entry.getValue().get() - scrabbleAvailableLetters[entry.getKey() - 'a']
  • 223. @JosePaumard#J8Stream 3) # of blanks for a word Java 8 Stream API – Rx Java // number of blanks for a given word Function<String, Long> nBlanks = word -> histoOfLetters.apply(word) .entrySet().stream() .mapToLong(blank) .sum();
  • 224. @JosePaumard#J8Stream 3) # of blanks for a word Java 8 Stream API – Rx Java // number of blanks for a given word Func1<String, Observable<Long>> nBlanks = word -> histoOfLetters.call(word) .flatMap(map -> Observable.from(() -> map.entrySet().iterator())) .flatMap(blank) .reduce(Long::sum) ;
  • 225. @JosePaumard#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)) ;
  • 226. @JosePaumard#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 letters Function<String, IntStream> first3 = word -> word.chars().limit(3);
  • 227. @JosePaumard#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 letters Func1<String, Observable<Integer>> first3 = word -> Observable.from( IterableSpliterator.of( word.chars().boxed().limit(3).spliterator() ) ) ;
  • 228. @JosePaumard#J8Stream 5) Bonus for a doubled letter – 2 Java 8 Stream API – Rx Java // Bonus for double letter ToIntFunction<String> bonusForDoubleLetter = word -> Stream.of(first3.apply(word), last3.apply(word)) .flatMapToInt(Function.identity()) .map(scoreOfALetter) .max() .orElse(0) ;
  • 229. @JosePaumard#J8Stream 5) Bonus for a doubled letter – 2 Java 8 Stream API – Rx Java // Bonus for double letter Func1<String, Observable<Integer>> bonusForDoubleLetter = word -> Observable.just(first3.call(word), last3.call(word)) .flatMap(observable -> observable) .flatMap(scoreOfALetter) .reduce(Integer::max) ;
  • 230. @JosePaumard#J8Stream 6) Final score of a word Java 8 Stream API – Rx Java // score of the word put on the board Function<String, Integer> score3 = word -> 2*(score2.apply(word) + bonusForDoubleLetter.applyAsInt(word)) + (word.length() == 7 ? 50 : 0);
  • 231. @JosePaumard#J8Stream 6) Final score of a word Java 8 Stream API – Rx Java // score of the word put on the board Func1<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) ;
  • 232. @JosePaumard#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() ) ) ;
  • 233. @JosePaumard#J8Stream 7) Histogram of the scores Java 8 Stream API – Rx Java Func1<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) ; }) ;
  • 234. @JosePaumard#J8Stream 8) Best word Java 8 Stream API – Rx Java // best key / value pairs List<Entry<Integer, List<String>>> finalList = buildHistoOnScore.apply(score3).entrySet() .stream() .limit(3) .collect(Collectors.toList()) ;
  • 235. @JosePaumard#J8Stream 8) Best word Java 8 Stream API – Rx Java // best key / value pairs 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) ; } ) .toBlocking() .first() ;
  • 236. @JosePaumard#J8Stream 8) Best word Java 8 Stream API – Rx Java // best key / value pairs CountDownLatch latch = new CountDownLatch(3) ; 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() ;
  • 237. @JosePaumard#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
  • 238. @JosePaumard#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
  • 239. @JosePaumard#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 Aleksey Shipilëv @shipilev Чувак из ТВ-службы пришёл отключать антенну. Оказался масс- спектрометристом, сцепился языком с тестем: стоят, обсуждают девайсы. #наукоград
  • 242. @JosePaumard#J8Stream JMH Launching a benchmark > mvn clean install > java –jar target/benchmark.jar
  • 243. @JosePaumard#J8Stream JMH 3 ways of measuring performances average execution time number of executions per second quantiles diagrams
  • 244. @JosePaumard#J8Stream Performances Average execution time Benchmark Mode Cnt Score Error Units NonParallelStreams avgt 100 29,027 ± 0,279 ms/op
  • 245. @JosePaumard#J8Stream Performances Average execution time Benchmark Mode Cnt Score Error Units NonParallelStreams avgt 100 29,027 ± 0,279 ms/op RxJava avgt 100 253,788 ± 1,421 ms/op
  • 246. @JosePaumard#J8Stream Performances Average execution time Benchmark Mode Cnt Score Error Units NonParallelStreams avgt 100 29,027 ± 0,279 ms/op RxJava avgt 100 253,788 ± 1,421 ms/op ParallelStreams avgt 100 7,624 ± 0,055 ms/op
  • 247. @JosePaumard#J8Stream Performances Average execution time RxJava spends a lot of time openning observables, due to the all flatMap patterns Benchmark Mode Cnt Score Error Units NonParallelStreams avgt 100 29,027 ± 0,279 ms/op RxJava avgt 100 253,788 ± 1,421 ms/op ParallelStreams avgt 100 7,624 ± 0,055 ms/op
  • 249. @JosePaumard#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
  • 250. @JosePaumard#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/
  • 251. @JosePaumard#J8Stream Conclusion Java 8 Streams: part of the JDK good performances, efficient memory footprint parallelization extensible through the Spliterator patterns
  • 252. @JosePaumard#J8Stream Conclusion With more to come in Java 9 Java 9 is bringing a reactive framework as part of java.util.concurrent http://openjdk.java.net/jeps/266 http://gee.cs.oswego.edu/dl/jsr166/dist/docs/index.html (Class Flow)
  • 254. Q / A