java 8 dos and don'ts - javabin oslo may 2015
TRANSCRIPT
2
Java 8 – what’s new?Lambdas
Method handles
Extension methods
Streams
Optional3
Java 8 – what’s new?Lambdas (anonymous functions)
Method handles
Extension methods
Streams
Optional4
5
Java 7 vs 8Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getName().compareTo(y.getName()); } });
6
Java 7 vs 8Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getName().compareTo(y.getName()); } });
vs
sort(people, (x, y) -> x.getName().compareTo(y.getName()));
7
Java 7 vs 8Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getName().compareTo(y.getName()); } });
vs
sort(people, comparing(person -> person.getName()));
8
Java 7 vs 8Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getName().compareTo(y.getName()); } });
vs
sort(people, comparing(Person::getName));
9
Java 7 vs 8Collections.sort(people, new Comparator<Person>() { public int compare(Person x, Person y) { return x.getName().compareTo(y.getName()); } });
vs
people.sort(comparing(Person::getName));
10
Streams
© Fredrik Vraalsen 2008
Old fashioned imperative
12
List<RoadData> filtered = new ArrayList<>();int count = 0; for (Iterator<RoadData> i = roadData.iterator(); i.hasNext() && count < 10; ) { RoadData data = i.next(); if (nameQuery.matches(data.getName())) { filtered.add(data); count++; }}
Streams
13
roadData.stream() .filter(data -> nameQuery.matches(data.getName())) .limit(10) .collect(toList());
Streams – pipelines
14
roadData.stream() .filter(data -> nameQuery.matches(data.getName())) .limit(10) .collect(toList());
cat roadData.txt | grep … | head > output.txt
Learn you a Stream API
15
Map<String, List<Article>> articlesByCategory =
Learn you a Stream API
16
Map<String, List<Article>> articlesByCategory = articleTransports.stream()
Learn you a Stream API
17
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(transport -> convertToArticle(transport))
Learn you a Stream API
18
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(transport -> convertToArticle(transport)) .collect(groupingBy(article -> article.getCategory()));
Learn you a Stream API
19
Method handles
20
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(transport -> convertToArticle(transport)) .collect(groupingBy(article -> article.getCategory()));
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(this::convertToArticle) .collect(groupingBy(article -> article.getCategory()));
Method handles
21
Method handles
22
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(this::convertToArticle) .collect(groupingBy(Article::getCategory));
Naming, caching, counting
23
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(this::convertToArticle) .collect(groupingBy(Article::getCategory));
Naming, caching, counting
24
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(this::transportToArticle) .collect(groupingBy(Article::category));
Extract functions
25
Map<String, List<Article>> articlesByCategory = articleTransports.stream() .map(transportToArticle) .collect(groupingBy(Article::category));
Function<ArticleTransport, Article> transportToArticle = transport -> convertToArticle(transport);
Lambdas everywhere!!!1!links.stream() .map(link -> link.build()) .forEach(abderaElement::addLink);
26
Old school ifs and forslinks.stream() .map(link -> link.build()) .forEach(abderaElement::addLink);
for (LinkBuilder lb : links) { abderaElement.addLink(lb.build()); }
27
Parsing nested JSON "suggest": { "tag_suggest": [ { "length": 5, "offset": 0, "options": [ { "freq": 25, "score": 0.8, "text": "fakta" } ], "text": "fanta" } ] } 28
Lambdas everywhere!!!1!List<String> terms = new ArrayList<>();
suggestions.getAsJsonObject().getAsJsonArray(“tag_suggest”) .forEach(tag -> tag.getAsJsonObject().getAsJsonArray("options") .forEach(option -> terms .add(option.getAsJsonObject().getAsJsonPrimitive("text") .getAsString())));
29
Old school ifs and forsList<String> terms = new ArrayList<>();
for (JsonElement tag : suggestions.getAsJsonObject().getAsJsonArray("tag_suggest")) { for (JsonElement option : tag.getAsJsonObject().getAsJsonArray("options")) { terms.add(option.getAsJsonObject().getAsJsonPrimitive("text").getAsString()); } }
30
Old school ifs and forsList<String> terms = new ArrayList<>();
for (JsonElement tag : getAll("tag_suggest", suggestions)) { for (JsonElement option : getAll("options", tag)) { terms.add(getString("text", option)); } }
31
List<String> terms = getAll("tag_suggest", suggestions).stream() .flatMap(tag -> getAll("options", tag).stream()) .map(option -> getString("text", option)) .collect(Collectors.toList());
32
Lambdas everywhere!!!1!
Readability ≫ Style / LOC
Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.
http://c2.com/cgi/wiki?CodeForTheMaintainer
OH NOES
NullPointerException!!?!© Fredrik Vraalsen 201
Optional<T>Wrapper object
Make explicit if a value is present or absent (empty)
35
Optional examplepublic Optional<Image> getImage(Article article)
---
36
Optional examplepublic Optional<Image> getImage(Article article)
---
Optional<Image> image = getImage(article);
37
Check presencepublic Optional<Image> getImage(Article article)
---
Optional<Image> image = getImage(article);if (image.isPresent()) { doSomething(image.get());}
38
Check presencepublic Optional<Image> getImage(Article article)
---
Optional<Image> image = getImage(article);image.ifPresent(img -> doSomething(img));
39
Check presencepublic Optional<Image> getImage(Article article)
---
getImage(article).ifPresent(image -> doSomething(image));
40
Default / fallback valuepublic Optional<Image> getImage(Article article)
---
Image image = getImage(article).orElse(defaultImage);
41
Optional in / Optional outpublic Optional<String> getCaption(Optional<Image> image)
---
Optional<Image> image = getImage(article);Optional<String> caption = getCaption(image);
42
Optional in / Optional outpublic String getCaption(Image image)
---
Optional<Image> image = getImage(article);Optional<String> caption = ???
43
Reaching into the void …public String getCaption(Image image)
---
Optional<Image> image = getImage(article);Optional<String> caption = image.map(img -> getCaption(img));
44
Reaching into the void …public String getCaption(Image image)
---
Optional<String> caption = getImage(article) .map(img -> getCaption(image));
45
Bye bye NullPointerException?Marker – this may not return/contain value
Public APIs
Not a general solution to NPEs
46
Optional + Streams = true?
47
Optional + Streams = true?
48
myStream.map(v -> functionReturningOptional(v))
Optional + Streams = true?
49
myStream.map(v -> functionReturningOptional(v))
Stream<Optional<T>>
Optional + Streams = true?
50
myStream.map(v -> functionReturningOptional(v))
Stream<Optional<T>> ⇒ Stream<T> ???
Guava Optional
51
Iterable<T> presentInstances(Iterable<Optional<T>> optionals)
Optional + Streams = true?
52
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article>
Optional + Streams = true?
53
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .map(article -> getImage(article)) // Stream<Optional<Image>>
Optional + Streams = true?
54
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .map(article -> getImage(article)) // Stream<Optional<Image>> .filter(Optional::ifPresent) .map(Optional::get) // Stream<Image>
Optional + Streams = true?
55
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .map(article -> getImage(article)) // Stream<Optional<Image>> .filter(Optional::ifPresent) .map(Optional::get) // Stream<Image> .collect(toList());
flatMap to the rescue!flatMap = map + flatten
Stream<Stream<T>> ⇒ Stream<T>
56
flatMap to the rescue!flatMap = map + flatten
Stream<Optional<T>> ⇒ Stream<T> ???
57
flatMap to the rescue!Easy to create helper functions
Stream<T> toStream(Optional<T> optValue)
58
http://stackoverflow.com/questions/22725537/using-java-8s-optional-with-streamflatmap
Optional + Streams = true?
59
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .map(article -> getImage(article)) // Stream<Optional<Image>> .filter(Optional::ifPresent) .map(Optional::get) // Stream<Image> .collect(toList());
Optional + Streams = true
60
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .flatMap(article -> toStream(getImage(article))) // Stream<Image> .collect(toList());
Optional + Streams = true
61
public Optional<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .flatMap(article -> getImage(article).stream()) // Stream<Image> .collect(toList());
Java 9
https://bugs.openjdk.java.net/browse/JDK-8050820
Take one stream and pass it around…
62
public Stream<Image> getImage(Article article)
---
List<Image> images = articles.stream() // Stream<Article> .flatMap(article -> getImage(article)) // Stream<Image> .collect(toList());
No method handle for you!
63
private Article elementToArticle(Map contentById, Element el)
---
List<Article> articles = elements.stream() .map(el -> elementToArticle(contentById, el)) .collect(toList())
64
http://en.wikipedia.org/wiki/Malabar_matthi_curry#/media/File:Meen_curry_2_(cropped).JPG
Yummy currying!!
65
Mapper mapper = new Mapper(contentById);
---
List<Article> articles = elements.stream() .map(el -> mapper.elementToArticle(el)) .collect(toList())
Yummy currying!!
66
Mapper mapper = new Mapper(contentById);
---
List<Article> articles = elements.stream() .map(mapper::elementToArticle) .collect(toList())
Performance
© Fredrik Vraalsen 2012
Streams – performanceList<Article> frontpageArticles = frontpage.getArticleIds().stream() .map(id -> fetchArticle(id)) .collect(toList());
68
This one goes to 11!List<Article> frontpageArticles = frontpage.getArticleIds().parallelStream() .map(id -> fetchArticle(id)) .collect(toList());
69
StarvationCommon F/J thread pool
Workarounds?
Execute within explicit F/J pool
Use CompletableFuture
70
CompletableFutureChaining of async futures and actions
Waiting for all or any future(s)
Explicitly complete (like Promise)
Control of executor service
71
http://blog.krecan.net/2014/03/18/how-to-specify-thread-pool-for-java-8-parallel-streams/http://www.nurkiewicz.com/2013/05/java-8-completablefuture-in-action.html
To parallelStream or not to …Batch?
parallelStream FTW!
Interactive? Concurrency?
CompletableFuture FTW!72
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri))
??? Try<RestResponse<ResolvedUri>>
}
73
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri)) .map(response -> response.getEntity())
??? Try<Optional<ResolvedUri>>
}
74
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri)) .map(response -> response.getEntity().get())
??? Try<ResolvedUri>
}
75
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri)) .map(response -> (ResolvedSectionUri) response.getEntity().get())
??? Try<ResolvedSectionUri>
}
76
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri)) .map(response -> (ResolvedSectionUri) response.getEntity().get()) .orElse(null);
}
77
Taking the happy path!Try<RestResponse<ResolvedUri>> resolveURI(URI uri)
---
public ResolvedSectionUri resolveSectionUri(String uri) { return client.resolveURI(uri)) .map(response -> (ResolvedSectionUri) response.getEntity().get()) .orElseGet(() -> { log.warn("Cannot resolve section from URI: {}", uri); return null; });}
78
https://github.com/lambdista/try
More cool stuff in Java 8String join
Collection removeIf (≈ filter)
Map getOrDefault, putIfAbsent, replace, forEach, etc.
java.util.Optional
java.util.stream.Collectors
count, sum, average, min, max, groupingBy, etc.
java.nio.file.Files lines79
Functional programmingSimpler code
More robust
Better performance
Higher levelDeclarative
Less verbose
Less bugs?
81
List<RoadData> filtered = new ArrayList<>();int count = 0; for (Iterator<RoadData> i = roadData.iterator(); i.hasNext() && count < 10; ) { RoadData data = i.next(); if (nameQuery.matches(data.getName())) { filtered.add(data); count++; } }
roadData.stream() .filter(data -> nameQuery.matches(data.getName())) .limit(10) .collect(toList());
vs.
Pure functions
82
Data In Data Out
Transformation
No external interactions
Functional core
83
————- —— ——— —- — —- —-—————————— —- — —- ——————— — — — ——-——- —- — —————- ——— ——————- —— ———— - —-———- — —- — -
Pure functionsI/O I/O
Building blocks
© Fredrik Vraalsen 201
What’s missing?© Fredrik Vraalsen 2012
What’s missing?Immutability
Value types
Data structures (lists, maps, etc.)
Concurrency
86
What’s the big deal?Functional programming is all about values!
And transformations (functions) computing new values
Parallellism vs. Concurrency
Robustness
Testability
87
Some help to be foundImmutable collections
Google Guava, FunctionalJava, clj-ds
Concurrency mechanisms
Akka (Actors, STM)
88
github.com/krukow/clj-dsPersistentVector<Person> people = Persistents.vector( new Person("Fredrik", 39), new Person("Hedda", 3));
89
github.com/krukow/clj-dsPersistentVector<Person> people = Persistents.vector( new Person("Fredrik", 39), new Person("Hedda", 3));
PersistentVector<Person> morePeople = people.plus(new Person("Johannes", 5));
90
github.com/krukow/clj-dsPersistentVector<Person> people = Persistents.vector( new Person("Fredrik", 39), new Person("Hedda", 3));
PersistentVector<Person> morePeople = people.plus(new Person("Johannes", 5));
morePeople.stream() .forEach(p -> System.out.println(p.getName()));
91
Why use X instead?Java 8 ready for enterprise dev?
JBoss AS, WebSphere – Nope
WildFly, GlassFish, WebLogic, Jetty, Tomcat – OK?
Important things are still missing from Java 8
Clojure and Scala available on JDK 6+!
92