90
23/03/2019 The Dark Side of Java 8 https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 1/90 The Dark Side of Java 8 The Dark Side of Java 8 Grzegorz Piwowarek Grzegorz Piwowarek @pivovarit @pivovarit

T h e Da r k S i d e of Jav a 8 - doag.org · T h e Da r k S i d e of Jav a 8 G r zego r z P i wow a rek @pivovarit. 23/03/2019 The Dark Side of Java 8 https:

  • Upload
    vanhanh

  • View
    212

  • Download
    0

Embed Size (px)

Citation preview

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 1/90

The Dark Side of Java 8The Dark Side of Java 8Grzegorz PiwowarekGrzegorz Piwowarek

@pivovarit@pivovarit

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 2/90

{ { } }Lead Backend Engineer @ Lead Backend Engineer @

Trainer @ Trainer @ , ,

4comprehension.com4comprehension.comCasumoTechCasumoTech

Bottega IT MindsBottega IT MindsOS ContributorOS Contributor DZone MVBDZone MVB

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 3/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 4/90

Java 8Java 8

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 5/90

https://twitter.com/mariofusco/status/957540001146986496

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 6/90

Feature-driven -> Cadence-drivenFeature-driven -> Cadence-driven

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 7/90

Feature-driven:Feature-driven:Java 7 - Strings in Switch StatementsJava 8 - Project LambdaJava 9 - Project JigSaw...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 8/90

Cadence-driven:Cadence-driven:Java 10 - 3.18Java 11 - 9.18Java 12 - 3.19...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 9/90

Java 12 - 3.19 �Java 12 - 3.19 �

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 10/90

LTS Releases:LTS Releases:Java 7Java 7Java 8Java 8

Java 9Java 9Java 10Java 10

Java 11Java 11Java 12Java 12

......

Java 17Java 17

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 11/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 12/90

#1 Conditional Stream#1 Conditional StreamTerminationTermination

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 13/90

List<LocalDate> getDates()

[2012-02-02, 2012-03-02, 2012-04-02, (...)]

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 14/90

Task: take all dates before XXXTask: take all dates before XXX

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 15/90

Works properly but evaluates the whole streamDoesn't work with in�nite streams

getDates().stream() .filter(date -> date.isBefore(LocalDate.of(2012, 4, 4))) .map(...) .forEach(System.out::println);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 16/90

2012-02-02, 2012-03-02, 2012-04-02,

-- POTENTIAL CUT OFF POINT --

2012-05-02, 2012-06-02, 2012-07-02, 2012-08-02, 2012-09-02, 2012-10-02, 2012-11-02, 2012-12-02, 2013-01-02, 2013-02-02, 2013-03-02, 2013-04-02, 2013-05-02, 2013-06-02, 2013-07-02, 2013-08-02, 2013-09-02, 2013-10-02, 2013-11-02, 2013-12-02,

...

getDates().stream() .peek(System.out::println) .filter(date -> date.isBefore(LocalDate.of(2012, 4, 4))) .map(...) .forEach(...);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 17/90

Solution: migrate to JDK9+Solution: migrate to JDK9+Stream#takeWhile/dropWhileStream#takeWhile/dropWhile

[JDK8] don't use Stream API if you want to be able to break out of it[JDK8] use limit() to cap the number of fetched elements (if applicable)

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 18/90

getDates().stream() .filter(date -> date.isBefore(LocalDate.of(2014, 4, 4))) .map(...) .forEach(System.out::println);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 19/90

The stream terminates as soon the �rst mismatch is encountered

getDates().stream() .takeWhile(date -> date.isBefore(LocalDate.of(2014, 4, 4))) .map(...) .forEach(System.out::println);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 20/90

#2 Stream#�atMap()#2 Stream#�atMap()

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 21/90

Streams ~ Lazy SequencesStreams ~ Lazy SequencesAs performant as imperative equivalents (time complexity)As performant as imperative equivalents (time complexity)

In theory.In theory.

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 22/90

return getUsers().stream() .flatMap(u -> u.getAddresses().stream()) .filter(address -> address.contains("1")) .findAny()

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 23/90

List<String> addresses = new ArrayList<>(); for (User u : getUsers()) { for (String address : u.getAddresses()) { if (address.contains("1")) { return address; // short-circuts the ongoing iteration } } }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 24/90

Not so true in practiceNot so true in practice

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 25/90

Task: take a �rst encountered address of a �rstTask: take a �rst encountered address of a �rstencountered userencountered user

static List<User> getUsers() { // db fetch stub return List.of(new User(List.of("a1","a2","a3","a4","a5"))); }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 26/90

getUsers().stream() .flatMap(u -> u.getAddresses().stream()) .findAny();

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 27/90

getUsers().stream() .flatMap(u -> u.getAddresses().stream()) .peek(System.out::println) .findAny();

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 28/90

a1 a2 a3 a4 a5

https://bugs.openjdk.java.net/browse/JDK-8075939https://bugs.openjdk.java.net/browse/JDK-8075939https://bugs.openjdk.java.net/browse/JDK-8189234https://bugs.openjdk.java.net/browse/JDK-8189234

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 29/90

getUsers().stream() .flatMap(u -> getAllAddresses(u)) // large/infinite stream .peek(System.out::println) .findAny();

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 30/90

It gets worse once we start adding more operations:It gets worse once we start adding more operations:getUsers().stream() .flatMap(u -> u.getAddresses().stream()) .map(a -> { System.out.println("making a super expensive call now"); return 42; }) .findAny();

making a super expensive call now making a super expensive call now making a super expensive call now making a super expensive call now making a super expensive call now

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 31/90

The causeThe cause

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 32/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 33/90

Solution: implement your own Spliterator-based lazySolution: implement your own Spliterator-based lazy�atMap()�atMap()

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 34/90

https://stackover�ow.com/a/32767282/2229438https://stackover�ow.com/a/32767282/2229438

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 35/90

Practical Solution: migrate to JDK10+Practical Solution: migrate to JDK10+JDK-8 Solution: don't use Stream API if you need nested collections to be evaluated lazilyJDK-9 Solution: see above

http://hg.openjdk.java.net/jdk/jdk10/rev/fca88bbbafb9http://hg.openjdk.java.net/jdk/jdk10/rev/fca88bbbafb9

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 36/90

#3 JDK9 Stream#takeWhile#3 JDK9 Stream#takeWhile

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 37/90

List<List<String>> list = List.of( List.of("1", "2"), List.of("3", "4", "5", "6", "7"));

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 38/90

list.stream() .flatMap(Collection::stream) .forEach(System.out::println);

1 2 3 4 5 6 7

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 39/90

Stream.of("1", "2", "3", "4", "5", "6", "7") .takeWhile(i -> !i.equals("4")) .forEach(System.out::println);

1 2 3

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 40/90

List<List<String>> list = List.of( List.of("1", "2"), List.of("3", "4", "5", "6", "7")); list.stream() .flatMap(Collection::stream) .takeWhile(i -> !i.equals("4")) .forEach(System.out::println);

1 2 3 5 6 7

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 41/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 42/90

Solution: migrate to JDK10+Solution: migrate to JDK10+

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 43/90

#4 Lambda Expressions vs.#4 Lambda Expressions vs.Checked ExceptionsChecked Exceptions

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 44/90

java.util.function.Functionjava.util.function.Function@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 45/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 46/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 47/90

Solution: use helper wrappersSolution: use helper wrappersgetUsers().stream() .map(unchecked(u -> new URL(u.webpage))) .collect(Collectors.toList());

https://github.com/pivovarit/throwing-functionhttps://github.com/pivovarit/throwing-function

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 48/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 49/90

A bound of the form “throws α” is purely informational: it directsresolution to optimize the instantiation of “α” so that, if

possible, it is not a checked exception type. (…)

Otherwise, if the bound set contains “throws αi”, and the properupper bounds of “αi” are, at most, Exception, Throwable, and

Object, then Ti = RuntimeException.https://docs.oracle.com/javase/specs/jls/se8/html/jls-18.htmlhttps://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 50/90

Simply put:Simply put:Every T in “<T extends Throwable>” is generously inferred to be

a RuntimeException if a more speci�c type can't be inferred.http://mail.openjdk.java.net/pipermail/lambda-dev/2013-February/007981.htmlhttp://mail.openjdk.java.net/pipermail/lambda-dev/2013-February/007981.html

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 51/90

static void rethrow(Exception t) throws Exception { throw t; }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 52/90

static <T extends Exception> void rethrow(Exception t) throws T { throw t; // Unhandled exception: java.lang.Exception }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 53/90

static <T extends Exception> void rethrow(Exception t) throws T { throw (T) t; // Just cast it, #YOLO }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 54/90

public static void main(String[] args) { rethrow(new Exception(":>")); // no try-catch needed :) }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 55/90

Let's put that into practiceLet's put that into practice

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 56/90

public interface ThrowingFunction<T, R> { R apply(T t) throws Exception; }

static <T, R> Function<T, R> sneaky(ThrowingFunction<T, R> f)

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 57/90

static <T, R> Function<T, R> sneaky(ThrowingFunction<T, R> f) { return t -> { try { return f.apply(t); } catch (Exception ex) { return ThrowingFunction.sneakyThrow(ex); } }; }

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 58/90

getUsers().stream() .map(sneaky(u -> new URL(u.webpage))) .map(sneaky(url -> url.openConnection()) .map(sneaky(c -> c.getInputStream())));

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 59/90

http://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/http://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 60/90

Just because you don’t like the rules, doesn’t mean its a goodidea to take the law into your own hands. Your advice is

irresponsible because it places the convenience of the codewriter over the far more important considerations of

transparency and maintainability of the program. by Brian Goetz

https://stackover�ow.com/questions/19757300/java-8-lambda-streams-�lter-by-method-with-exception#comment54437053_19757456

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 61/90

#5 Parallel Streams#5 Parallel Streams

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 62/90

Parallel processing made easy™Parallel processing made easy™

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 63/90

Parallel processing made easy (?)™Parallel processing made easy (?)™

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 64/90

SequentialSequentialgetDates().stream() .map(...) .forEach(System.out::println);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 65/90

ParallelParallelgetDates().parallelStream() .map(...) .forEach(System.out::println);

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 66/90

Ctrl + RCtrl + R

Not a very good idea.Not a very good idea.

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 67/90

Multiple questions arise:Multiple questions arise:...but where are those tasks run?...but where are those tasks run?

...in the cloud?...in the cloud?...in the blockchain?...in the blockchain?

...how to provide a custom thread pool?...how to provide a custom thread pool?...what's the maximum number of tasks executed in parallel?...what's the maximum number of tasks executed in parallel?

......

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 68/90

Code inspection reveals:Code inspection reveals:

Implementation detailA thread pool that is used for execution of parallel streams is unspeci�ed

static final ForkJoinPool common;

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 69/90

public final ForkJoinTask<V> fork()

Arranges to asynchronously execute this task in the pool thecurrent task is running in (...)

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 70/90

The size of the computation will be in proportion to the common pool and notThe size of the computation will be in proportion to the common pool and notthe custom pool.the custom pool.

Fixed in JDK10 - https://bugs.openjdk.java.net/browse/JDK-8190974Fixed in JDK10 - https://bugs.openjdk.java.net/browse/JDK-8190974

ForkJoinPool customPool = new ForkJoinPool(42); customPool.submit( () -> getDates().parallelStream().forEach(e -> {}));

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 71/90

ForkJoinPool Settings:ForkJoinPool Settings:The parallelism levelForkJoinWorkerThreadFactoryUncaughtExceptionHandlerasyncMode

Since JDK 9:Since JDK 9:corePoolSizemaximumPoolSizeminimumRunnablesaturation allowedkeepAliveTime

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 72/90

Note, however, that this technique of submitting a task to afork-join pool to run the parallel stream in that pool is an

implementation “trick” and is not guaranteed to work. by Stuart Marks

https://stackover�ow.com/questions/28985704/parallel-stream-from-a-hashset-doesnt-run-in-parallel/29272776#29272776

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 73/90

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 74/90

Which is faster? Sequential or Parallel?Which is faster? Sequential or Parallel?SequentialSequential

Random rand = new Random(); int[] array = new int[90000000]; Arrays.stream(array) .map(i -> rand.nextInt()) .boxed() .collect(Collectors.toList());

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 75/90

Which is faster? Sequential or Parallel?Which is faster? Sequential or Parallel?ParallelParallel

Random rand = new Random(); int[] array = new int[90000000]; Arrays.stream(array).parallel() .map(i -> rand.nextInt()) .boxed() .collect(Collectors.toList());

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 76/90

Parallel - doesn't always mean fasterParallel - doesn't always mean faster

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 77/90

#6 Stream#generate#6 Stream#generate

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 78/90

/** * Returns an infinite sequential unordered stream where each element is * generated by the provided {@code Supplier}. This is suitable for * generating constant streams, streams of random elements, etc. * * @param <T> the type of stream elements * @param s the {@code Supplier} of generated elements * @return a new infinite sequential unordered {@code Stream} */ public static<T> Stream<T> generate(Supplier<T> s)

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 79/90

Stream.generate(() -> 42) .forEach(System.out::println); // 42 // 42 // 42 // ...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 80/90

Stream.generate(rand::nextInt) .forEach(System.out::println); // ${some.random.value1} // ${some.random.value2} // ${some.random.value3} // ...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 81/90

Stream.generate(new Supplier<Integer>() { private int value; @Override public Integer get() { return value++; }}) .limit(8) .forEach(System.out::println);

1 2 3 4 5 6 7 8

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 82/90

Stream.generate(new Supplier<Integer>() { private int value; @Override public Integer get() { return value++; }}).parallel() .limit(8) .forEach(System.out::println);

0 2 4 7 6 8 1 3

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 83/90

Stream.generate(new Supplier<Integer>() { private AtomicInteger value = new AtomicInteger(); @Override public Integer get() { return value.getAndIncrement(); }}).parallel() .limit(20) .forEach(System.out::println);

0 1 2 3 4 5 7 6 ...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 84/90

List<Integer> result = Stream.generate(new Supplier<Integer>() { private final AtomicInteger value = new AtomicInteger(); @Override public Integer get() { return value.getAndIncrement(); }}) .parallel() .peek(System.out::println) .limit(4) .collect(Collectors.toList());

i " "// 0 // 6 // 7 // 5 // 3 // 4 // 2 // 1 // 8 // 9 results: [5, 6, 0, 7]

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 85/90

/** * Returns an in�nite sequential UNORDERED stream whereeach element is * generated by the provided Supplier. */

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 86/90

#7 Optional vs Option#7 Optional vs Option

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 87/90

Nulls are interpreted by Optional as Optional.empty()

User user = ... Optional.ofNullable(user) .map(o -> o.getAddress()) // getAddress() returns null .ifPresent(System.out::println); //

scala> Some(null)

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 88/90

Two different results!

users.stream() .map(o -> o.getAddress()) .map(this::handleAddress) // handles null properly .findAny() ... users.stream() .findAny() .map(o -> o.getAddress()) .map(this::handleAddress) // null never makes it here ...

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 89/90

Key takeaway:Key takeaway:Java sucks, let's PHPJava sucks, let's PHP

It's worth paying attention and migrating to new minor JDK releases. SmallIt's worth paying attention and migrating to new minor JDK releases. Smallthings matter.things matter.

Also, read the docs.Also, read the docs.

23/03/2019 The Dark Side of Java 8

https://pivovarit.github.io/talks/java-8-dark-side/?print-pdf#/ 90/90Twitter/GitHub: @pivovarit

Thank You!Thank You!

{ { } }

https://pivovarit.github.io/talks/java-8-dark-sidehttps://pivovarit.github.io/talks/java-8-dark-side

@[email protected]