FunctionalOptionalStream & Vegtables
@FunctionalInterface
One method to rule them all
public class AnonymousInnerClassTest {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("A thread created and running ...");
}
}).start();
}
}
At first, There was chaos
Lambda Expressions
To the rescue
public class AnonymousInnerClassTest {
public static void main(String[] args) {
new Thread(() ->
System.out.println("A thread created and running ..."))
.start();
}
}
"Let there be light"
and there was light
Method::signatures
let it divide the water from the water
public class Program {
public static void main(String[] args) {
new Thread(Program::printThreadCreatedMessage).start();
}
public static void printThreadCreatedMessage() {
System.out.println("A thread created and running ...");
}
}
The Dome
Divided the water under the dome from the water above
Old dog new tricks
@FunctionalInterface
public interface Runnable {
void run();
}
Functional Interface
born to help the ignorant
If to speak the truth
Any interface with just one method unimplemented (do'nt forget there are default methods now) will work
Method reference > Lambda expressions
- Lambda expressions tend to be code smell
- Method reference express the what and not the how
- Method reference encapsulates complexity
Instance Method
public class Program {
public static void main(String[] args) {
Arrays.asList("Saar", "Efes", ";)").stream()
.map(String::length).forEach(System.out::println);
}
}
of an arbitrary object of a particular type
Instance Method
public class Program {
public static void main(String[] args) {
Program program = new Program();
new Thread(program::aRunnablePossibleMethod).start();
}
public void aRunnablePossibleMethod() {
System.out.println("A thread created and running ...");
}
}
of a particular object
Static Method
public class Program {
public static void main(String[] args) {
Arrays.asList("Saar", "Efes", ";)").stream()
.map(Integer::valueOf).forEach(System.out::println);
}
}
Constructor Reference
public class Program {
public static void main(String[] args) {
Integer willReturnOne = Optional.of(1)
.orElseThrow(IllegalAccessException::new);
}
}
public class AnonymousInnerClassTest {
public static void main(String[] args) {
Integer willReturnOne = Optional.of(1)
.orElseThrow(() -> new IllegalAccessException());
}
}
Same as
Optional<T>
When NullPointerExceptions are no longer fun
The Class
104 lines including imports
public final class Optional<T> {
private final T value;
public static <T> Optional<T> empty();
public static <T> Optional<T> of(T arg);
public static <T> Optional<T> ofNullable(T arg);
public T get();
public boolean isPresent();
public void ifPresent(Consumer<? super T> arg0);
public Optional<T> filter(Predicate<? super T> arg0);
public <U> Optional<U> map(Function<? super T, ? extends U> arg0);
public <U> Optional<U> flatMap(Function<? super T, Optional<U>> arg0);
public T orElse(T arg0);
public T orElseGet(Supplier<? extends T> arg0);
public <X extends Throwable> T orElseThrow(Supplier<? extends X> arg0) throws X;
}
Optional
What is it good for
Clarifies Intent
Removes uncertainty
No more null checks
Clarifies Intent
Any reader or consumer of an API will be beaten over the head with the fact that there might be nothing there and that a check is necessary before accessing the value.
public class Program {
private static MeshekService meshekService;
public static void main(String[] args) {
Optional<Meshek> aMeshek = meshekService.findOne(meshekId);
return aMeshek.orElseThrow(WrongIdGivenException::new);
}
}
Removes Uncertainty
Without Optional the meaning of a null occurrence is unclear:
- Legal representation of a stateĀ
- Implementation error e.g. a missing field or failed initialization.
No more null checks
Now nothing can be null anymore. Whether with annotations, assertions or plain checks, you never have to think about whether this argument or that return type can be null. It can't!
What gives
String version = "UNKNOWN";
if(computer != null){
Soundcard soundcard = computer.getSoundcard();
if(soundcard != null){
USB usb = soundcard.getUSB();
if(usb != null){
version = usb.getVersion();
}
}
}
String usbVersion = computer
.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
String usbVersion =
computer?.getSoundcard()?.getUSB()?.getVersion() ?: "UNKNOWN";
C#
C#
C#
C#
C#
C#
C#
C#
C#
C#
C#
C#
Arrays.asList("a1", "a2", "b1", "c2", "c1")
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
// Prints:
// C1
// C2
Represents a sequence of elements and supports different kind of operations to perform computations upon those elements.
Intermediate
- map
- filter
- sorted
- mapToInt
Terminal
- forEach
- collect
- findAny
- anyMatch
Stream Operations
Processing Order
Stream.of("d2", "a2", "b1", "b3", "c")
.map(s -> {
System.out.println("map: " + s);
return s.toUpperCase();
})
.anyMatch(s -> {
System.out.println("anyMatch: " + s);
return s.startsWith("A");
});
// Prints:
// map: d2
// anyMatch: D2
// map: a2
// anyMatch: A2
Stream.of("d2", "a2", "b1", "b3", "c")
.sorted((s1, s2) -> {
System.out.printf("sort: %s; %s\n", s1, s2);
return s1.compareTo(s2);
})
.filter(s -> {
System.out.println("filter: " + s);
return s.startsWith("a");
})
.map(s -> {
System.out.println("map: " + s);
return s.toUpperCase();
})
.forEach(s -> System.out.println("forEach: " + s));
// sort: a2; d2
// sort: b1; a2
// sort: b1; d2
// sort: b1; a2
// sort: b3; b1
// sort: b3; d2
// sort: c; b3
// sort: c; d2
// filter: a2
// map: a2
// forEach: A2
// filter: b1
// filter: b3
// filter: c
// filter: d2
Primitive Streams
DoubleStream
IntStream
LongStream
Primitives Operations
- min
- max
- average
- and more...
stream.mapToInt
Parallel Stream
Streams can be executed in parallel to increase runtime performance on large amount of input elements. Parallel streams use a common ForkJoinPool...
Arrays.asList("a1", "a2", "b1", "c2", "c1")
.parallelStream()
.filter(s -> {
System.out.format("filter: %s [%s]\n",
s, Thread.currentThread().getName());
return true;
})
.map(s -> {
System.out.format("map: %s [%s]\n",
s, Thread.currentThread().getName());
return s.toUpperCase();
})
.forEach(s -> System.out.format("forEach: %s [%s]\n",
s, Thread.currentThread().getName()));
filter: b1 [main]
filter: a2 [ForkJoinPool.commonPool-worker-1]
map: a2 [ForkJoinPool.commonPool-worker-1]
filter: c2 [ForkJoinPool.commonPool-worker-3]
map: c2 [ForkJoinPool.commonPool-worker-3]
filter: c1 [ForkJoinPool.commonPool-worker-2]
map: c1 [ForkJoinPool.commonPool-worker-2]
forEach: C2 [ForkJoinPool.commonPool-worker-3]
forEach: A2 [ForkJoinPool.commonPool-worker-1]
map: b1 [main]
forEach: B1 [main]
filter: a1 [ForkJoinPool.commonPool-worker-3]
map: a1 [ForkJoinPool.commonPool-worker-3]
forEach: A1 [ForkJoinPool.commonPool-worker-3]
forEach: C1 [ForkJoinPool.commonPool-worker-2]
IntSummaryStatistics ageSummary =
persons
.stream()
.collect(Collectors.summarizingInt(p -> p.age));
System.out.println(ageSummary);
// Prints:
// IntSummaryStatistics{count=4, sum=76, min=12,
// average=19.000000, max=23}
Map<Integer, List<Person>> personsByAge = persons
.stream()
.collect(Collectors.groupingBy(p -> p.age));
personsByAge
.forEach((age, p) ->
System.out.format("age %s: %s\n", age, p));
// Prints:
// age 18: [Max]
// age 23: [Peter, Pamela]
// age 12: [David]
String phrase = persons
.stream()
.filter(p -> p.age >= 18)
.map(p -> p.name)
.collect(Collectors.joining(" and ", "In Germany ",
" are of legal age."));
System.out.println(phrase);
// Prints:
// In Germany Max and Peter and Pamela are of legal age.
String phrase = persons
.stream()
.filter(p -> p.age >= 18)
.map(p -> p.name)
.collect(Collectors.joining(" and ", "In Germany ",
" are of legal age."));
System.out.println(phrase);
// Prints:
// In Germany Max and Peter and Pamela are of legal age.
Collector<Person, StringJoiner, String> personNameCollector =
Collector.of(
() -> new StringJoiner(" | "), // supplier
(j, p) -> j.add(p.name.toUpperCase()), // accumulator
(j1, j2) -> j1.merge(j2), // combiner
StringJoiner::toString); // finisher
String names = persons
.stream()
.collect(personNameCollector);
System.out.println(names); // MAX | PETER | PAMELA | DAVID
Questions?
FunctionalOptionalStream
By Boaz Berman
FunctionalOptionalStream
Java 8 features: FunctionalInterface, Optional container & Stream.
- 147