persons.stream()
.filter(p -> p.getAge() > 20)
.map(p -> fetchDetailsAsync(p))
.map(pdf -> pdf.thenCompose(pd -> sendEmail(pd)))
.map(emailF -> emailF.handle((email, e) -> complete(email, e)));
Matej Lazar [[email protected]]([email protected])
???
Visit [http://matejonnet.github.io/get-rid-of-boilerplate-with-j8/] (http://matejonnet.github.io/get-rid-of-boilerplate-with-j8/) to see slides in presentation mode.
-
Lambda is a function, function takes parameters and returns result
-
Pre Java 8 functions could be implemented using methods
-
A Lambda enables functions to be passed around
-
Default method: method in interface (you don't break back compatibility)
-
Method references "::" are used for lambda shortcuts
-
Higher order function takes a function and creates new function
Runnable r1 = new Runnable(){
@Override
public void run(){
System.out.println("Hello world one!");
}
};
Runnable r2 = () -> System.out.println("Hello world two!");
-
Is an interface where you have to implement single method (single abstract method)
-
collections
- Predicate
- Comparator
-
java.util.function
- Supplier
- Consumer
- Function<T,R>
-
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
list.sort((String o1, String o2) -> o1.compareTo(o2));
list.sort((o1, o2) -> o1.compareTo(o2));
persons.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
//Higher order function
persons.sort(Comparator.comparing(p -> p.getName()));
//Method references
persons.sort(Comparator.comparing(Person::getName));
persons.sort(comparing(Person::getName));
persons.sort(comparing(Person::getAge).thenComparing(Person::getName));
Useful default methods added to list and collection interfaces
Removing element from list and avoiding ConcurrentModificationException
-
no classical for loop -> iterator.remove
-
collection.removeIf
for (Person person : persons) { if (person.getName().startsWith("B")) { persons.remove(person); } }
persons.removeIf(p -> p.getName().startsWith("B"));
Similar: list.replaceAll
- forEach
- stream
- filter(predicate)
- map
- collect (collector / reducer)
- java.util.stream.Collectors
- SingletonCollector
- string concatenating
for (Person person : persons) {
System.out.println(person.getName());
}
persons.forEach(p -> System.out.println(p.getName()));
//System.out.println(p)
persons.forEach(System.out::println);
List<String> personNamesOver20 = persons.stream()
.filter(p -> p.getAge() > 20)
.map(Person::getName)
.collect(Collectors.toList());
int totalAge = persons.stream()
.map(Person::getAge)
.reduce(0, (a, b) -> a + b);
int totalAgeWithSum = persons.stream()
.mapToInt(Person::getAge)
.sum();
Remove elements form stream
List<Person> personsOver20 = persons.stream()
//.filter(p -> p.getAge() > 20)
//.filter(filterAge20)
.filter(filterAge(20))
.collect(Collectors.toList());
String personsString = persons.stream()
.filter(p -> p.getAge() > 20)
.sorted(Comparator.comparing(Person::getName))
.map(Person::getName)
.collect(Collectors.joining(", "));
With formatting
String personsString = persons.stream()
.filter(p -> p.getAge() > 20)
.sorted(Comparator.comparing(Person::getName))
.map(p -> p.getName() + " is " + p.getAge() + " years old.")
//.map(formatString)
.collect(Collectors.joining("\n"));
Reduces result to single instance
Person person = persons.stream()
.filter(p -> p.getId() == 1)
.collect(StreamCollectors.singletonCollector());
- Reactive programming
- Extending Future
- Exception handling
- Reactive programming is programming with asynchronous data streams
- A stream is a sequence of ongoing events ordered in time
- We capture these emitted events asynchronously, by defining a function that will execute when a value is emitted
- Observer Design Pattern
- Extends Future by adding async support
- .complete(T value)
- .completeExceptionally(Throwable ex)
- .get() -> inherited from Future blocking
- .then* -> async
- .thenCompose(Function) -> function is called on complete
- .handle(BiFunction(T result, Throwable e))
CompletableFuture<String> future = new CompletableFuture<>();
new Thread(() -> longRunningTask(future)).start();
//blocks until future.complete is called
future.get();
private void longRunningTask(CompletableFuture<String> future) {
//long running operations
future.complete("42");
}
Calling complete unblocks all clients waiting for get and also calls functions that are referenced by .then* methods.
final CompletableFuture<String> future =
CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
//...long running...
return "42";
}
}, executor);
final CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
//...long running...
return "42";
}, executor);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
sleepQuietly();
return "42";
}, executor);
future.thenApply(Integer::parseInt)
.thenApply(r -> r * r * Math.PI)
.thenAccept(p -> System.out.println("Result :" + p.toString()));
-
Only runtime exceptions can be thrown out of lambda
-
All exceptions must be wrapped in RuntimeException
-
Main thread completed we cannot catch the exception
-
The most flexible approach is using .handle()
-
handle() takes a function receiving either correct result or exception
future.thenApply(Integer::parseInt) .thenApply(r -> r * r * Math.PI) .thenAccept((p) -> System.out.println("Result :" + p.toString())) .handle((result, ex) -> { if (result != null) storeResult(result); else handleException(ex); });
Combining (chaining) two futures (thenCompose())
public void combining(Person person) {
fetchDetailsAsync(person)
.thenCompose(pd -> sendEmail(pd))
.handle((email, e) -> complete(email, e));
}
private CompletableFuture<PersonWithDetails> fetchDetailsAsync(Person person) {
return CompletableFuture.supplyAsync(() -> {
return new PersonWithDetails(person);
}, executor);
}
persons.parallelStream()
.filter(p -> p.getAge() > 20)
.map(p -> fetchDetailsAsync(p))
.map(pdf -> pdf.thenCompose(pd -> sendEmail(pd)))
.map(emailF -> emailF.handle((email, e) -> complete(email, e)));
Oracle Lambda-QuickStart
Java SE 8 - lntroduction to Lambda Expressions
http://www.nurkiewicz.com/2013/05/java-8-definitive-guide-to.html
https://gist.github.com/Unisay/ff1aefdbd840c574395c
https://github.com/gnab/remark/
Matej Lazar ([email protected], [email protected])