The document discusses Java 8 features like lambda expressions, streams, and method references. It provides examples of filtering a list of books by pages or genre using lambda expressions and streams. Lambda expressions allow implementing functional interfaces concisely without anonymous classes. Streams provide a way to process data elements sequentially and support operations like filtering, mapping, matching, reducing, and collecting results.
Report
Share
Report
Share
1 of 66
Download to read offline
More Related Content
Functional Java 8 in everyday life
1. Functional Java 8
in everyday life
The code is available on:
https://github.com/andreaiacono/Java8
2. Functional Java8 in everyday life
What's new in Java 8
•Default methods
•Lambda expressions
•Streams
•Optionals
•Date/Time API
Biggest update since Generics in Java 1.5
3. Functional Java8 in everyday life
Background
Anonymous inner classes let define a functional
behaviour, but with a lot of code:
JButton testButton = new JButton("Test Button");
testButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Click!");
}
});
All we need is a way to write only the code
in the method.
4. Functional Java8 in everyday life
Lambda expressions
provide a clear and concise way to represent a ”one abstract method
interface” (a so-called functional interface) using an expression:
JButton testButton = new JButton("Test Button");
testButton.addActionListener(event -> System.out.println("Click!"));
A lambda is composed of three parts:
Argument list Arrow token Body of the method
event → System.out.println("Click!")
It works because the listener has only one abstract method and the
compiler can infer what to do from the interface:
package java.awt.event;
import java.util.EventListener;
public interface ActionListener extends EventListener {
/**
* Invoked when an action occurs.
*/
public void actionPerformed(ActionEvent e);
}
5. Functional Java8 in everyday life
Lambda expressions
Variations in signatures:
Signature Argument
list
Arrow
token Body of the method
void execute() () → System.out.println("foo!")
String getString() () → "foo"
Integer increment(Integer value) (value) → new Integer(value +1)
String concatenate(String a, String b) (a, b) → a.toString() + b.toString()
void process(T t) (t) → {}
6. Data setup
public class Book {
private List<Author> authors;
private String title;
private int pages;
private Genre genre;
private int year;
private String Isbn;
}
public class Author {
private String name;
private String lastName;
private String country;
}
public enum Genre {
NOVEL, SHORT_NOVEL, NON_FICTION;
}
Functional Java8 in everyday life
7. Functional Java8 in everyday life
Lambda sample
We need to find the books with more than 400 pages.
public List getLongBooks(List books) {
List accumulator = new ArrayList<>();
for (Book book : books) {
if (book.getPages() > 400) {
accumulator.add(book);
}
}
return accumulator;
}
Now the requirements has changed and we also need to filter for
genre of the book:
public List getLongNonFictionBooks(List books) {
List accumulator = new ArrayList<>();
for (Book book : books) {
if (book.getPages() > 400 && Genre.NON_FICTION.equals(book.getGenre())) {
accumulator.add(book);
}
}
return accumulator;
}
We need a different method for every filter,
while the only change is the if condition!
8. Functional Java8 in everyday life
Lambda sample
We can use a lambda. First we define a functional interface,
which is an interface with only one abstract method:
@FunctionalInterface
public interface BookFilter {
public boolean test(Book book);
}
Then we can define a generic filter and write as many
implementation we want in just one line:
public static List lambdaFilter(List books, BookFilter bookFilter) {
List accumulator = new ArrayList<>();
for (Book book : books) {
if (bookFilter.test(book)) {
accumulator.add(book);
}
}
return accumulator;
}
// one line filters
List longBooks = lambdaFilter(Setup.books, b -> b.getPages() > 400);
BookFilter nflbFilter = b -> b.getPages() > 400 && Genre.NON_FICTION == b.getGenre();
List longNonFictionBooks = lambdaFilter(Setup.books, nflbFilter);
9. Functional Java8 in everyday life
Functional interfaces
We don't need to write all the functional interfaces because
Java 8 API defines the basic ones in java.util.function package:
Functional interface Descriptor Method name
Predicate<T> T → boolean test()
BiPredicate<T, U> (T, U) → boolean test()
Consumer<T> T → void accept()
BiConsumer<T, U> (T, U) → void accept()
Supplier<T> () → T get()
Function<T, R> T → R apply()
BiFunction<T, U, R> (T, U) → R apply()
UnaryOperator<T> T → T identity()
BinaryOperator<T> (T, T) → T apply()
So we did not need to write the BookFilter interface, because
the Predicate interface has exactly the same descriptor.
10. Functional Java8 in everyday life
Lambda sample
So we can rewrite our code as:
public static List lambdaFilter(List books, Predicate bookFilter) {
List accumulator = new ArrayList<>();
for (Book book : books) {
if (bookFilter.test(book)) {
accumulator.add(book);
}
}
return accumulator;
}
// one line filters
List longBooks = lambdaFilter(Setup.books, b -> b.getPages() > 400);
Predicate nflbFilter = b -> b.getPages() > 400 && Genre.NON_FICTION == b.getGenre();
List longNonFictionBooks = lambdaFilter(Setup.books, nflbFilter);
11. Functional Java8 in everyday life
Lambdas and existing interfaces
Since in JDK there are a lot of interfaces with only one
abstract method, we can use lambdas also for them:
// Runnable interface defines void run() method
Runnable r = () -> System.out.println("I'm running!");
r.run();
// Callable defines T call() method
Callable callable = () -> "This is a callable object";
String result = callable.call();
// Comparator defines the int compare(T t1, T t2) method
Comparator bookLengthComparator = (b1, b2) -> b1.getPages() - b2.getPages();
Comparator bookAgeComparator = (b1, b2) -> b1.getYear() - b2.getYear();
12. Functional Java8 in everyday life
Method reference
Sometimes code is more readable if we refer just to the method
name instead of a lambda
Kind of method reference Example
To a static method Integer::parseInt
To an instance method of a class Integer::intValue
To an instance method of an object n::intValue
To a constructor Integer::new
So we can rewrite this lambda
Function<String, Integer> lengthCalculator = (String s) -> s.length();
with a method reference:
Function<String, Integer> lengthCalculator = String::length;
13. Functional Java8 in everyday life
Comparators
In former versions of Java, we had to write an anonymous
inner class to speficy the behaviour of a Comparator:
Collections.sort(users, new Comparator<Author>() {
public int compare(Author a1, Author a2) {
return a1.compareTo(a2.id);
}
});
We can use lambda for making code more readable:
// now sort is a oneliner!
Collections.sort(authors, (Author a1, Author a2) -> a1.compareTo(a2));
14. Functional Java8 in everyday life
Imagine we want to cache
results from DB queries.
This is a first rough version
(too duplicated logic)
class DbCache {
public static enum QueryType {
BOOKS_COUNT, PUBLISHERS_COUNT, COUNTRIES_COUNT;
}
private static Map cache = new HashMap<>();
public static Integer getValue(QueryType queryType) {
Integer count;
switch (queryType) {
case BOOKS_COUNT:
if (cache.containsKey(queryType)) {
return cache.get(queryType);
}
count = countBooks();
cache.put(queryType, count);
return count;
case PUBLISHERS_COUNT:
if (cache.containsKey(queryType)) {
return cache.get(queryType);
}
count = countPublishers();
cache.put(queryType, count);
return count;
case COUNTRIES_COUNT:
if (cache.containsKey(queryType)) {
return cache.get(queryType);
}
count = countCountries();
cache.put(queryType, count);
return count;
}
}
private static Integer countBooks() {
return 4; // returns a value got from DB query
}
}
// cache call:
Integer booksCount = DbCache.getValue(QueryType.BOOKS_COUNT);
15. Functional Java8 in everyday life
A bit more polished, but still an ”execute around” pattern:
class DbCache {
private static Map cache = new HashMap<>();
public static enum QueryType {
BOOKS_COUNT, PUBLISHERS_COUNT, COUNTRIES_COUNT;
}
public static Integer getValue(QueryType queryType) {
Integer count = cache.get(queryType);
if (count == null) {
switch (queryType) {
case BOOKS_COUNT:
count = countBooks();
break;
case PUBLISHERS_COUNT:
count = countPublishers();
break;
case COUNTRIES_COUNT:
count = countCountries();
break;
}
}
cache.put(queryType, count);
}
return count;
}
private static Integer countBooks() {
// returns a value got from DB query
return 4;
}
}
// cache call:
Integer booksCount = DbCache.getValue(QueryType.BOOKS_COUNT);
16. Functional Java8 in everyday life
Using interfaces the result is better, but still verbose:
class InterfaceCache {
private static Map cache = new HashMap<>();
public static enum QueryType {
BOOKS_COUNT, PUBLISHERS_COUNT, COUNTRIES_COUNT;
}
public static Integer getValue(QueryType queryType, Counter counter) {
Integer count = cache.get(queryType);
if (count == null) {
count = counter.count();
cache.put(queryType, count);
}
return count;
}
}
interface Counter {
public Integer count();
}
class BooksCounter implements Counter {
@Override
public Integer count() {
// returns a value got from DB query
return 4;
}
}
// other Counter implementations
// cache call:
BooksCounter bookCounter = new BooksCounter();
Integer booksCount = getValue(QueryType.BOOKS_COUNT, bookCounter);
17. Functional Java8 in everyday life
We can rewrite the cache with lambdas:
class FunctionalCache {
private static Map cache = new HashMap<>();
public static enum QueryType {
BOOKS_COUNT, PUBLISHERS_COUNT, COUNTRIES_COUNT;
}
public static Integer getValue(QueryType queryType, Function counter) {
Integer count = cache.get(queryType);
if (count == null) {
count = counter.apply(queryType);
cache.put(queryType, count);
}
return count;
}
private static Integer countBooks() {
// returns a value got from DB query
return 4;
}
// other counts from DB..
}
// cache call:
Integer booksCount = FunctionalCache.getValue(QueryType.BOOKS_COUNT, f -> countBooks());
18. Functional Java8 in everyday life
Or we can put the DB queries inside the cache:
class FunctionalMapCache {
private static enum QueryType {
BOOKS_COUNT(() -> countBooks()),
PUBLISHERS_COUNT(() -> countPublishers()),
COUNTRIES_COUNT(() -> countCountries());
private Supplier counter;
QueryType(Supplier counter) {
this.counter = counter;
}
public Supplier getCounter() {
return counter;
}
}
private static Map cache = new HashMap<>();
public static Integer getValue(QueryType queryType) {
Integer count = cache.get(queryType);
if (count == null) {
count = queryType.getCounter().get();
cache.put(queryType, count);
}
return count;
}
private static Integer countBooks() {
// returns a value got from DB query
return 4;
}
// other counts from DB..
}
// cache call:
Integer booksCount = getValue(QueryType.BOOKS_COUNT);
19. Functional Java8 in everyday life
Streams
The Java Collections framework relies on the concept of
external iteration, as in the example below:
for (Book book: books) {
book.setYear = 1900;
}
compared to internal iteration, like the example below:
Books.forEach(b -> book.setYear(1900));
The difference is not only in code readabilty and
maintainability, is also related to performance: the runtime
can optimize the internal iteration for parallelism, lazyness or
reordering the data.
20. Functional Java8 in everyday life
Streams
Let's see again the book filter we wrote with lambdas:
public static List lambdaFilter(List books, Predicate bookFilter) {
List accumulator = new ArrayList<>();
for (Book book : books) {
if (bookFilter.test(book)) {
accumulator.add(book);
}
}
return accumulator;
}
// one line filters
List longBooks = lambdaFilter(Setup.books, b -> b.getPages() > 400);
Predicate nflbFilter = b -> b.getPages() > 400 && Genre.NON_FICTION == b.getGenre();
List longNonFictionBooks = lambdaFilter(Setup.books, nflbFilter);
We can rewrite it using streams:
// stream based filters
List longBooks = books.stream().filter(b -> b.getPages() > 400).collect(toList());
List longNonFictionBooks =
books.stream().filter(b -> b.getPages() > 400 && Genre.NON_FICTION == b.getGenre())
.collect(toList());
The code is much cleaner now, because we don't need the
lambdaFilter() method anymore. Let's see how it works.
21. Functional Java8 in everyday life
Streams
List longBooks = books.stream().filter(b -> b.getPages() > 400).collect(toList());
What we've done is:
• calling the stream() method on the collection, for trasforming it
into a stream
• calling the filter() method passing a Predicate, for filtering
the elements of the stream dropping any/some of them
• calling the collect() method with the static import toList()
for collecting the filtered elements and put them into a List
object
23. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages.
24. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages. Here's how:
List<Book> longBooks =
books.stream().filter(b -> b.getPages() > 400).collect(toList());
25. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages. Here's how:
List<Book> longBooks =
books.stream().filter(b -> b.getPages() > 400).collect(toList());
We need the top three longest books.
26. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages. Here's how:
List<Book> longBooks =
books.stream().filter(b -> b.getPages() > 400).collect(toList());
We need the top three longest books. Here's how:
List<Book> top3LongestBooks =
books.stream().sorted((b1,b2) -> b2.getPages()-b1.getPages()).limit(3).Collect( toList());
27. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages. Here's how:
List<Book> longBooks =
books.stream().filter(b -> b.getPages() > 400).collect(toList());
We need the top three longest books. Here's how:
List<Book> top3LongestBooks =
books.stream().sorted((b1,b2) -> b2.getPages()-b1.getPages()).limit(3).Collect( toList());
We need from the fourth to the last longest books.
28. Functional Java8 in everyday life
Streams samples
We need all the books with more than 400 pages. Here's how:
List<Book> longBooks =
books.stream().filter(b -> b.getPages() > 400).collect(toList());
We need the top three longest books. Here's how:
List<Book> top3LongestBooks =
books.stream().sorted((b1,b2) -> b2.getPages()-b1.getPages()).limit(3).Collect( toList());
We need from the fourth to the last longest books. Here's how:
List<Book> fromFourthLongestBooks =
books.stream().sorted((b1,b2) -> b2.getPages()-b1.getPages()).skip(3).collect(toList());
29. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years.
30. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years. Here's how:
List<Integer> publishingYears =
books.stream().map(b -> b.getYear()).distinct().collect(toList());
31. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years. Here's how:
List<Integer> publishingYears =
books.stream().map(b -> b.getYear()).distinct().collect(toList());
We need all the authors.
32. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years. Here's how:
List<Integer> publishingYears =
books.stream().map(b -> b.getYear()).distinct().collect(toList());
We need all the authors. Here's how:
Set<Author> authors =
books.stream().flatMap(b -> b.getAuthors().stream()).distinct().collect(toSet());
33. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years. Here's how:
List<Integer> publishingYears =
books.stream().map(b -> b.getYear()).distinct().collect(toList());
We need all the authors. Here's how:
Set<Author> authors =
books.stream().flatMap(b -> b.getAuthors().stream()).distinct().collect(toSet());
We need all the origin countries of the authors.
34. Functional Java8 in everyday life
Streams samples
We need to get all the publishing years. Here's how:
List<Integer> publishingYears =
books.stream().map(b -> b.getYear()).distinct().collect(toList());
We need all the authors. Here's how:
Set<Author> authors =
books.stream().flatMap(b -> b.getAuthors().stream()).distinct().collect(toSet());
We need all the origin countries of the authors. Here's how:
Set<String> countries =
books.stream().flatMap(b -> b.getAuthors().stream())
.map(author -> author.getCountry()).distinct().collect(toSet());
35. Functional Java8 in everyday life
Optionals
Let's start with an example: ISBN in 2007 has changed from
10 to 13 characters. To check which version of ISBN a book
has we have to write:
boolean isPre2007 = book.getIsbn().length() > 10;
What if a book was published before 1970, when ISBN did not
exist and the property ISBN is null? Without a proper check,
NullPointerException will be thrown at runtime!
Java 8 has introduced the java.util.Optional class. The
code of our Book class can be now written as:
public class Book {
private List<Author> authors;
private String title;
private int pages;
private Optional<String> Isbn;
private Genre genre;
private int year;
}
36. Functional Java8 in everyday life
Optionals
We can set the value with:
book.setIsbn(Optional.of("978000000"));
Or, if the book was published before 1970:
book.setIsbn(Optional.empty());
Or, if we don't know the value in advance:
book.setIsbn(Optional.ofNullable(value));
(in case value is null an empty Optional will be set)
We can now get the value with:
Optional<String> isbn = book.getIsbn();
System.out.println("Isbn: " + isbn.orElse("NOT PRESENT");
If the Optional contains an ISBN it will be returned,
otherwise the string "NOT PRESENT" will be returned.
37. Functional Java8 in everyday life
Other streams samples
We want the most recent published book.
38. Functional Java8 in everyday life
Other streams samples
We want the most recent published book. Here's how:
Optional<Book> lastPublishedBook =
books.stream().min(Comparator.comparingInt(Book::getYear));
39. Functional Java8 in everyday life
Other streams samples
We want the most recent published book. Here's how:
Optional<Book> lastPublishedBook =
books.stream().min(Comparator.comparingInt(Book::getYear));
We want to know if all the books are written by more
than one author.
40. Functional Java8 in everyday life
Other streams samples
We want the most recent published book. Here's how:
Optional<Book> lastPublishedBook =
books.stream().min(Comparator.comparingInt(Book::getYear));
We want to know if all the books are written by more
than one author. Here's how:
boolean onlyShortBooks =
books.stream().allMatch(b -> b.getAuthors().size() > 1);
41. Functional Java8 in everyday life
Other streams samples
We want the most recent published book. Here's how:
Optional<Book> lastPublishedBook =
books.stream().min(Comparator.comparingInt(Book::getYear));
We want to know if all the books are written by more
than one author. Here's how:
boolean onlyShortBooks =
books.stream().allMatch(b -> b.getAuthors().size() > 1);
We want one of the books written by more than one
author.
42. Functional Java8 in everyday life
Other streams samples
We want the most recent published book. Here's how:
Optional<Book> lastPublishedBook =
books.stream().min(Comparator.comparingInt(Book::getYear));
We want to know if all the books are written by more
than one author. Here's how:
boolean onlyShortBooks =
books.stream().allMatch(b -> b.getAuthors().size() > 1);
We want one of the books written by more than one
author. Here's how:
Optional<Book> multiAuthorBook =
books.stream().filter((b -> b.getAuthors().size() > 1)).findAny();
43. Functional Java8 in everyday life
Streams samples
We want the total number of pages published.
44. Functional Java8 in everyday life
Streams samples
We want the total number of pages published. Here's how:
Integer totalPages =
books.stream().map(Book::getPages).reduce(0, (b1, b2) -> b1 + b2);
Optional<Integer> totalPages =
or:
books.stream().map(Book::getPages).reduce(Integer::sum);
45. Functional Java8 in everyday life
Streams samples
We want the total number of pages published. Here's how:
Integer totalPages =
books.stream().map(Book::getPages).reduce(0, (b1, b2) -> b1 + b2);
Optional<Integer> totalPages =
or:
books.stream().map(Book::getPages).reduce(Integer::sum);
We want to know how many pages the longest book has.
46. Functional Java8 in everyday life
Streams samples
We want the total number of pages published. Here's how:
Integer totalPages =
books.stream().map(Book::getPages).reduce(0, (b1, b2) -> b1 + b2);
Optional<Integer> totalPages =
or:
books.stream().map(Book::getPages).reduce(Integer::sum);
We want to know how many pages the longest book has.
Here's how:
Optional<Integer> longestBook =
books.stream().map(Book::getPages).reduce(Integer::max);
47. Functional Java8 in everyday life
The Collector interface
The Collector interface was introduce to give developers a set of
methods for reduction operations.
Method Return type
toList() List<T>
toSet() Set<t>
toCollection() Collection<T>
counting() Long
summingInt() Long
averagingInt() Double
joining() String
maxBy() Optional<T>
minBy() Optional<T>
reducing() ...
groupingBy() Map<K, List<T>>
partioningBy() Map<Boolean, List<T>>
48. Functional Java8 in everyday life
Collector samples
We want the average number of pages of the books.
49. Functional Java8 in everyday life
Collector samples
We want the average number of pages of the books. Here's how:
Double averagePages =
books.stream().collect(averagingInt(Book::getPages));
50. Functional Java8 in everyday life
Collector samples
We want the average number of pages of the books. Here's how:
Double averagePages =
books.stream().collect(averagingInt(Book::getPages));
We want all the titles of the books.
51. Functional Java8 in everyday life
Collector samples
We want the average number of pages of the books. Here's how:
Double averagePages =
books.stream().collect(averagingInt(Book::getPages));
We want all the titles of the books. Here's how:
String allTitles =
books.stream().map(Book::getTitle).collect(joining(", "));
52. Functional Java8 in everyday life
Collector samples
We want the average number of pages of the books. Here's how:
Double averagePages =
books.stream().collect(averagingInt(Book::getPages));
We want all the titles of the books. Here's how:
String allTitles =
books.stream().map(Book::getTitle).collect(joining(", "));
We want the book with the higher number of authors. Here's how:
Optional<Book> higherNumberOfAuthorsBook =
books.stream().collect(maxBy(comparing(b -> b.getAuthors().size())));
53. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year.
54. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year. Here's how:
Map<Integer, List<Book>> booksPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear));
55. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year. Here's how:
Map<Integer, List<Book>> booksPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear));
We want a Map of how many books are published per year per
genre.
56. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year. Here's how:
Map<Integer, List<Book>> booksPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear));
We want a Map of how many books are published per year per
genre. Here's how:
Map<Integer, Map<Genre, List<Book>>> booksPerYearPerGenre =
Setup.books.stream().collect(groupingBy(Book::getYear, groupingBy(Book::getGenre)));
57. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year. Here's how:
Map<Integer, List<Book>> booksPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear));
We want a Map of how many books are published per year per
genre. Here's how:
Map<Integer, Map<Genre, List<Book>>> booksPerYearPerGenre =
Setup.books.stream().collect(groupingBy(Book::getYear, groupingBy(Book::getGenre)));
We want to count how many books are published per year.
58. Functional Java8 in everyday life
Stream grouping
We want a Map of book per year. Here's how:
Map<Integer, List<Book>> booksPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear));
We want a Map of how many books are published per year per
genre. Here's how:
Map<Integer, Map<Genre, List<Book>>> booksPerYearPerGenre =
Setup.books.stream().collect(groupingBy(Book::getYear, groupingBy(Book::getGenre)));
We want to count how many books are published per year.
Here's how:
Map<Integer, Long> bookCountPerYear =
Setup.books.stream().collect(groupingBy(Book::getYear, counting()));
59. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover.
60. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover. Here's how:
Map<Boolean, List<Book>> hardCoverBooks =
books.stream().collect(partitioningBy(Book::hasHardCover));
61. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover. Here's how:
Map<Boolean, List<Book>> hardCoverBooks =
books.stream().collect(partitioningBy(Book::hasHardCover));
We want to further classify book by genre.
62. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover. Here's how:
Map<Boolean, List<Book>> hardCoverBooks =
books.stream().collect(partitioningBy(Book::hasHardCover));
We want to further classify book by genre. Here's how:
Map<Boolean, Map<Genre, List<Book>>> hardCoverBooksByGenre =
books.stream().collect(partitioningBy(Book::hasHardCover,groupingBy(Book::getGenre)));
63. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover. Here's how:
Map<Boolean, List<Book>> hardCoverBooks =
books.stream().collect(partitioningBy(Book::hasHardCover));
We want to further classify book by genre. Here's how:
Map<Boolean, Map<Genre, List<Book>>> hardCoverBooksByGenre =
books.stream().collect(partitioningBy(Book::hasHardCover,groupingBy(Book::getGenre)));
We want to count books with/without hardcover.
64. Functional Java8 in everyday life
Stream partitioning
We want to classify book by hardcover. Here's how:
Map<Boolean, List<Book>> hardCoverBooks =
books.stream().collect(partitioningBy(Book::hasHardCover));
We want to further classify book by genre. Here's how:
Map<Boolean, Map<Genre, List<Book>>> hardCoverBooksByGenre =
books.stream().collect(partitioningBy(Book::hasHardCover,groupingBy(Book::getGenre)));
We want to count books with/without hardcover. Here's how:
Map<Boolean, Long> count =
books.stream().collect(partitioningBy(Book::hasHardCover, counting()));
65. Functional Java8 in everyday life
What we did not see:
• Parallel streams
• Streams methods for primitive types
66. Functional Java8 in everyday life
Thanks!
The code is available on:
https://github.com/andreaiacono/Java8