Download - Javaslang @ Devoxx
#Devoxx #Javaslang @koenighotze
JΛVΛSLΛNGFunctional Sugar For Java
#Devoxx #Javaslang @koenighotze
Senacor Technologies Programmer!
That’s me coding Scala
David Schmitz / @koenighotzeSenacor Technologies
Programmer! That’s me coding Scala
#Devoxx #Javaslang @koenighotze
What’s in it for you?Functional programming is hip
How Javaslang helped us
Examples, Code!
#Devoxx #Javaslang @koenighotze
Functors, applicatives,
monads and friends stay home
#Devoxx #Javaslang @koenighotze
Code that is easier to reason about
#Devoxx #Javaslang @koenighotze
Side-effects are eviltry { int i = 1/0; } catch (Throwable t) { … }Exceptions are goto-statements
:(
#Devoxx #Javaslang @koenighotze
Referential TransparencyMath.random();
Math.max(1, 2);
Math.random();
Math.max(1, 2);
Pure functions are a Good ThingTm
:(
#Devoxx #Javaslang @koenighotze
Thinking in ValuesImmutability
Performance
Safety
#Devoxx #Javaslang @koenighotze
In a nutshell, think about “what to code“
not “how to code”
#Devoxx #Javaslang @koenighotze
Enter Java 8(a) -> a + 2
list.stream().filter…
Excitement…
#Devoxx #Javaslang @koenighotze
“Try filtering all invalid users from a list of users”
#Devoxx #Javaslang @koenighotze
Excitement?…untilusers.stream() .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotzePainting by Gustav Courbet
#Devoxx #Javaslang @koenighotze
import static javaslang.API.*;
+
#Devoxx #Javaslang @koenighotze
What we’ll coverImmutable collections
Some functional sugar
Pattern matching
#Devoxx #Javaslang @koenighotze
Before we get to the details… Let’s fix that ugly code
#Devoxx #Javaslang @koenighotze
Fixing Things….users.stream() .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotze
Functional collectionsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotze
No need for CollectorsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}) .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotze
No need for CollectorsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}); .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotze
Wrapping ExceptionsList.ofAll(users) .filter(user -> { try { return user.validate(); } catch (Exception ex) { return false; }}); .collect(Collectors.toList());
#Devoxx #Javaslang @koenighotze
Wrapping ExceptionsList.ofAll(users) .filter(user ->
Try.of(user::validateAddress) .getOrElse(false) ); } catch (IllegalStateException ex) { return ); .collect(Collectors.toList();
#Devoxx #Javaslang @koenighotze
List.ofAll(users) List.filter(user -> Try.of(user::validateAddress) .getOrElse(false));
“Try filtering all invalid users from a list of users”
#Devoxx #Javaslang @koenighotze
Immutable Collections Image by Douglas Muth, https://flic.kr/p/acFwxG
#Devoxx #Javaslang @koenighotze
Mutable Collections are Evil
Returning void == Side-Effect!
interface Collection<E> { … void clear(); }
interface Collection<E> { … void clear(); }
#Devoxx #Javaslang @koenighotze
Easy solution? Collections
Collections .unmodifiableList(list); .add("BUMM");
#Devoxx #Javaslang @koenighotze
Easy solution? Collections
Collections .unmodifiableList(list) .add("BUMM");
#Devoxx #Javaslang @koenighotze
#Devoxx #Javaslang @koenighotze
Javaslang CollectionsList<~> t = List.of(“F95”);
List<~> t2 = t.append(withName(“FCK”));
F95 /t
#Devoxx #Javaslang @koenighotze
ImmutableList<~> t = List.of(“F95”);
List<~> t2 = t.prepend(“FCK”);
F95 /t
FCKt2
#Devoxx #Javaslang @koenighotze
List<~> t = List.of(“F95”);
List<~> t2 = t.prepend(“FCK”);
F95 /
FCK
t
t2
Persistent and Efficient
#Devoxx #Javaslang @koenighotze
Streams are glorified IteratorsStream<String> jdk = Stream.of("a", “B");
jdk.map(String::toUpperCase); jdk.map(String::toLowerCase);
#Devoxx #Javaslang @koenighotze
java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203) at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94) at java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:618) at java.util.stream.ReferencePipeline$3.<init>(ReferencePipeline.java:187) at java.util.stream.ReferencePipeline.map(ReferencePipeline.java:186)
#Devoxx #Javaslang @koenighotze
Javaslang StreamsStream<String> slang = Stream.of("a", "B"); slang.map(String::toUpperCase); // “A”,“B” slang.map(String::toLowerCase); // “a”,“b”
#Devoxx #Javaslang @koenighotze
Javaslang StreamsStream<String> slang = Stream.of("a", "B"); slang.map(String::toUpperCase) .take(2); slang.map(String::toLowerCase) .take(2);
#Devoxx #Javaslang @koenighotze
Javaslang StreamsStream<String> slang = Stream.of("a", "B"); slang.map(String::toUpperCase) .take(2);// “A”,“B” slang.map(String::toLowerCase) .take(2);// “a”,“b”
#Devoxx #Javaslang @koenighotze
Functional data structures improve performance and
reduce the chance of unexpected behaviour
#Devoxx #Javaslang @koenighotze
Functional Sugar
#Devoxx #Javaslang @koenighotze
“Find a user and, if an address is available, fetch
the user’s street”
#Devoxx #Javaslang @koenighotze
Cascading Pile of ShameUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
We’ve got java.util.Optional
Optional<User> opt = Optional.ofNullable(user);
if (optional.isPresent()) { … }
#Devoxx #Javaslang @koenighotze
#Devoxx #Javaslang @koenighotze
Please stop usingOptional#isPresent()
#Devoxx #Javaslang @koenighotze
An Option is like a Gift Box
NoneSome
#Devoxx #Javaslang @koenighotze
Map opens the Gift Box
MapSome Some
( )->
#Devoxx #Javaslang @koenighotze
Nothing from Nothing( )->
MapNone None
#Devoxx #Javaslang @koenighotze
Optional or Option?
Optional
#Devoxx #Javaslang @koenighotze
Optional or Option?
Option
Some None
#Devoxx #Javaslang @koenighotze
Optional or Option?
Option
Some None
Value
Iterable
#Devoxx #Javaslang @koenighotze
Optional or Option?
Option
Some None
Value
Iterable
#Devoxx #Javaslang @koenighotze
Optional or Option?
Option
Some None
Value
Iterable
Serializable
#Devoxx #Javaslang @koenighotze
Fixing the Pile of ShameUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
Option all the ThingsUser user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
Option all the ThingsOption<User> user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
Option all the ThingsOption<User> user = repo.findOne("id"); if (user != null) { Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
Option all the ThingsOption<User> user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
Option<User> user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } } Option<Address> getAddress()
#Devoxx #Javaslang @koenighotze
Option all the ThingsOption<User> user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); if (null != address) {
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
Option all the ThingsOption<User> user = repo.findOne("id"); user.flatMap(User::getAddress) Address address = user.getAddress(); .map(Address::getStreet)
return address.getStreet(); } }
#Devoxx #Javaslang @koenighotze
repo.findOne("id") .flatMap(User::getAddress) .map(Address::getStreet) .getOrElse("");
“Find a user and, if an address is available, fetch the user’s street”
#Devoxx #Javaslang @koenighotze
Option and map transform nested code into an
understandable story
#Devoxx #Javaslang @koenighotze
Working with legacy codePainting by Eero Järnefelt
#Devoxx #Javaslang @koenighotze
Nice Validation Codepublic static String check(String iban){ if (validationMagic(iban)) { return iban; }
throw new IllegalArgumentException(“Peng”); }
#Devoxx #Javaslang @koenighotze
Awesome WTF Code String iban; try { iban = check("AL47"); } catch (IllegalArgumentException ex) { iban = ""; }
#Devoxx #Javaslang @koenighotze
From Exceptions to Options
String iban = lift(Iban::check) .apply("AL47...") .getOrElse("");
#Devoxx #Javaslang @koenighotze
From Exceptions to Options
String iban = lift(Iban::check) .apply("AL47...") .getOrElse("");
#Devoxx #Javaslang @koenighotze
Wrapping Exceptions with Try
Try.of(() -> stuffToDo())
#Devoxx #Javaslang @koenighotze
Wrapping Exceptions with Try
FailureException
SuccessResult
Try.of(() -> stuffToDo())
#Devoxx #Javaslang @koenighotze
Exceptions to Options with Try
Try.of(() -> check("AL..")) .getOrElse("")
#Devoxx #Javaslang @koenighotze
Exceptions to Options with Try
Try.of(() -> check("AL..")) .getOrElse("")
#Devoxx #Javaslang @koenighotze
Lifting and Try-ing reduce exception handling clutter
and side-effects
#Devoxx #Javaslang @koenighotze
Structural DecompositionImage by Arend, https://flic.kr/p/pkBe4g
#Devoxx #Javaslang @koenighotze
Classic HTTP Handlingif (OK.equals(res.getStatusCode())) { return res.getBody(); }
return emptyList();
#Devoxx #Javaslang @koenighotze
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Pattern Matching Basics
#Devoxx #Javaslang @koenighotze
Pattern Matching Basics
Match(expression) .of(cases)
#Devoxx #Javaslang @koenighotze
Cases map functions to patterns
Case(pattern, function)
#Devoxx #Javaslang @koenighotze
Example Patterns
$() wildcard pattern $(“foo”) equals pattern isIn(“a”, “b”) conditional pattern
#Devoxx #Javaslang @koenighotze
HTTP Handling Fixed
*Note: some type details missing
Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );
#Devoxx #Javaslang @koenighotze
Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );
HTTP Handling Fixed
*Note: some type details missing
OK or anything else
#Devoxx #Javaslang @koenighotze
HTTP Handling Fixed
*Note: some type details missing
Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );
#Devoxx #Javaslang @koenighotze
HTTP Handling Fixed
*Note: some type details missing
Match(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );
#Devoxx #Javaslang @koenighotze
HTTP Handling FixedMatch(res.getStatusCode()) .of( Case($(OK), res.getBody()), Case($(), emptyList()) );
*Note: some type details missing
#Devoxx #Javaslang @koenighotze
Matching a Try
public Try<…> fetchFromUrl(…) { … }
#Devoxx #Javaslang @koenighotze
Matching a TryMatch(fetchFromUrl(“…”)) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );
#Devoxx #Javaslang @koenighotze
Matching a TryMatch(fetchFromUrl(“…”)) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );
#Devoxx #Javaslang @koenighotze
Matching a TryMatch(fetchFromUrl(“…”)) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );
#Devoxx #Javaslang @koenighotze
Presto!Match(fetchFromUrl(“…”)) .of( Case(Success($()), identity()), Case(Failure($()), emptyList()) );
#Devoxx #Javaslang @koenighotze
Pattern matching replaces complex if-then-else sequences
with clear expressions
#Devoxx #Javaslang @koenighotze
HashMap.of("Foo", "Bar", "Qux", "Baz") .bimap(String::toLowerCase, String::toUpperCase) .get("qux"); // BAZ
Javaslang offers much more
#Devoxx #Javaslang @koenighotze
Javaslang offers much moreTuple.of("Foo", 1) .map((s, i) -> Tuple.of(s + "Bar", i + 5)) // “FooBar”, 6
#Devoxx #Javaslang @koenighotze
Javaslang offers much more
#Devoxx #Javaslang @koenighotze
So, is this is the mother of all free lunches?
#Devoxx #Javaslang @koenighotze
What are the drawbacks?
#Devoxx #Javaslang @koenighotze
What are the drawbacks?count(Collection-libs)
>
count(Logging-libs)
#Devoxx #Javaslang @koenighotze
What are the drawbacks?Option.of(foo)
.map
.filter
.flatMap
#Devoxx #Javaslang @koenighotze
Wrapping upSlick, stable, consistent API
Object-functional
Complex(?)
Version 3 in 2017
#Devoxx #Javaslang @koenighotze
.iohttp://
Do you want to know more?
#Devoxx #Javaslang @koenighotze
Thank You!<[email protected]>