SlideShare a Scribd company logo
Łukasz

Biały
Functional

Java 8



Introduction
Scala / Java Developer
lbialy@virtuslab.com
What is functional
programming?
What is functional
programming?
• usage of pure functions
What is functional
programming?
• usage of pure functions
• expressions instead of statements
What is functional
programming?
• usage of pure functions
• expressions instead of statements
• widespread immutability
What is functional
programming?
• usage of pure functions
• expressions instead of statements
• widespread immutability
• referential transparency
What is functional
programming?
• usage of pure functions
• expressions instead of statements
• widespread immutability
• referential transparency
• lazy evaluation
What is functional
programming?
• usage of pure functions
• expressions instead of statements
• widespread immutability
• referential transparency
• lazy evaluation
... and functional idioms!
What's the gain?
What's the gain?
• More predictable execution (same arguments
always yield the same results)
What's the gain?
• More predictable execution (same arguments
always yield the same results)
• Easier to reason about
What's the gain?
• More predictable execution (same arguments
always yield the same results)
• Easier to reason about
• Easier to enforce strict type correctness
What's the gain?
• More predictable execution (same arguments
always yield the same results)
• Easier to reason about
• Easier to enforce strict type correctness
• more precise checks in compile time
What's the gain?
• More predictable execution (same arguments
always yield the same results)
• Easier to reason about
• Easier to enforce strict type correctness
• more precise checks in compile time
• less bugs in runtime
How does this relate to Java at all?
How does this relate to Java at all?
java.lang.NullPointerException
at org.springsource.loaded.agent.SpringLoadedPreProcessor.tryToEnsureSystemClassesInitialized(SpringLoadedPreProcessor.java:362)
at org.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:128)
at org.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:102)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:265)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:419)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1299)
at org.springframework.beans.factory.support.AbstractBeanFactory.access$000(AbstractBeanFactory.java:109)
at org.springframework.beans.factory.support.AbstractBeanFactory$4.run(AbstractBeanFactory.java:1265)
at org.springframework.beans.factory.support.AbstractBeanFactory$4.run(AbstractBeanFactory.java:1263)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1263)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:575)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1347)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:358)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:327)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:437)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:626)
at com.xxx.core.web.WebApplicationContext.invokeBeanFactoryPostProcessors(WebApplicationContext.java)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
at com.xxx.core.web.WebApplicationContext.refresh(WebApplicationContext.java)
...
Most common errors in Java
Most common errors in Java
• Takipi monitoring service analysed error logs of over 1k
enterprise apps
Most common errors in Java
• Takipi monitoring service analysed error logs of over 1k
enterprise apps
• 29,965,285 exceptions over 30 days
Most common errors in Java
• Takipi monitoring service analysed error logs of over 1k
enterprise apps
• 29,965,285 exceptions over 30 days
• Just 10 exception types generated 97,3% of all errors
Most common errors in Java
• Takipi monitoring service analysed error logs of over 1k
enterprise apps
• 29,965,285 exceptions over 30 days
• Just 10 exception types generated 97,3% of all errors
• Two most common: NullPointerException &
NumberFormatException
Most common errors in Java
• Takipi monitoring service analysed error logs of over 1k
enterprise apps
• 29,965,285 exceptions over 30 days
• Just 10 exception types generated 97,3% of all errors
• Two most common: NullPointerException &
NumberFormatException
http://blog.takipi.com/we-crunched-1-billion-java-logged-errors-heres-what-causes-97-of-them/
http://blog.takipi.com/the-top-10-exceptions-types-in-production-java-applications-based-on-1b-events/
How can FP help?
How can FP help?
• Functional style makes implicit rules governing code
explicit, often as a part of type signatures
How can FP help?
• Functional style makes implicit rules governing code
explicit, often as a part of type signatures
• Functional style avoids constructs that are not statically
analysable like throwing exceptions, therefore allowing
compiler to do it's job better
How can FP help?
• Functional style makes implicit rules governing code
explicit, often as a part of type signatures
• Functional style avoids constructs that are not statically
analysable like throwing exceptions, therefore allowing
compiler to do it's job better
• In concurrent and parallel programming lack of mutable
state removes whole classes of programming errors for free
How can FP help?
• Functional style makes implicit rules governing code
explicit, often as a part of type signatures
• Functional style avoids constructs that are not statically
analysable like throwing exceptions, therefore allowing
compiler to do it's job better
• In concurrent and parallel programming lack of mutable
state removes whole classes of programming errors for free
• Yields an elegant and concise code :)
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
• not feeling especially bright today?
have a NullPointerException in
runtime
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
• not feeling especially bright today?
have a NullPointerException in
runtime
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
• not feeling especially bright today?
have a NullPointerException in
runtime
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
• not feeling especially bright today?
have a NullPointerException in
runtime
• null is a subtype of every reference
type, so it will be propagated as 

a valid object value
1 package com.example;
2
3 class CharacterOps {
4
5 static Character firstCharacter(String string) {
6 return (string.length() > 0) ? string.charAt(0) : null;
7 }
8
9 static Integer getAlphabetPosition(Character character) {
10 int code = (int) character;
11
12 if (isLowerCase(code))
13 return code - 96;
14 else if (isUpperCase(code))
15 return code - 64;
16 else
17 return null; // or throw exception?
18 }
19
20 private static boolean isLowerCase(int code) {
21 return code >= 97 && code <= 122;
22 }
23
24 private static boolean isUpperCase(int code) {
25 return code >= 65 && code <= 90;
26 }
27
28 }
Optionality

of values
• optionality of value is not explicitly
known from method signature
• not feeling especially bright today?
have a NullPointerException in
runtime
• null is a subtype of every reference
type, so it will be propagated as 

a valid object value
• tracking null's origination point is so
much fun!
What we want:

composability
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
What we want:

composability
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• feeding function a "cat" is
fine, we get 3 as result
What we want:

composability
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• feeding function a "cat" is
fine, we get 3 as result
java.lang.NullPointerException
at com.example.CharacterOps.getAlphabetPosition(CharacterOps.java:10)
at com.example.CharOpsTest.testComposability(CharOpsTest.java:14)
What we want:

composability
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• feeding function a "cat" is
fine, we get 3 as result
• doesn't work so well for 

an empty string though
java.lang.NullPointerException
at com.example.CharacterOps.getAlphabetPosition(CharacterOps.java:10)
at com.example.CharOpsTest.testComposability(CharOpsTest.java:14)
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class ActualCharOpsTest {
8
9 @Test
10 public void testNullChecks() {
11
12 Character firstChar = firstCharacter("cat");
13
14 if (null == firstChar) {
15 // oops. what now? exception? propagate null?
16 } else {
17 // will throw NPE on digit :(
18 Integer position = getAlphabetPosition(firstChar);
19 // ...
20 }
21
22 }
23
24 }
What we get:

explicit null checks
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class ActualCharOpsTest {
8
9 @Test
10 public void testNullChecks() {
11
12 Character firstChar = firstCharacter("cat");
13
14 if (null == firstChar) {
15 // oops. what now? exception? propagate null?
16 } else {
17 // will throw NPE on digit :(
18 Integer position = getAlphabetPosition(firstChar);
19 // ...
20 }
21
22 }
23
24 }
• you have to remember to
check for null explicitly or
face NPE hunting
What we get:

explicit null checks
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class ActualCharOpsTest {
8
9 @Test
10 public void testNullChecks() {
11
12 Character firstChar = firstCharacter("cat");
13
14 if (null == firstChar) {
15 // oops. what now? exception? propagate null?
16 } else {
17 // will throw NPE on digit :(
18 Integer position = getAlphabetPosition(firstChar);
19 // ...
20 }
21
22 }
23
24 }
• you have to remember to
check for null explicitly or
face NPE hunting
• methods don't compose
anymore
What we get:

explicit null checks
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class ActualCharOpsTest {
8
9 @Test
10 public void testNullChecks() {
11
12 Character firstChar = firstCharacter("cat");
13
14 if (null == firstChar) {
15 // oops. what now? exception? propagate null?
16 } else {
17 // will throw NPE on digit :(
18 Integer position = getAlphabetPosition(firstChar);
19 // ...
20 }
21
22 }
23
24 }
• you have to remember to
check for null explicitly or
face NPE hunting
• methods don't compose
anymore
• ugly :(
What we get:

explicit null checks
1 package com.example;
2
3 import java.util.Optional;
4
5 class SafeCharOps {
6
7 static Optional<Character> firstCharacter(
8 String string
9 ) {
10 return (string.length() > 0) ?
11 Optional.of(string.charAt(0)) :
12 Optional.empty();
13 }
14
15 static Optional<Integer> getAlphabetPosition(
16 Character character
17 ) {
18 int code = (int) character;
19
20 return isLowerCase(code) ? Optional.of(code - 96) :
21 isUpperCase(code) ? Optional.of(code - 64) :
22 Optional.empty();
23 }
24
25 private static boolean isLowerCase(int code) {
26 return code >= 97 && code <= 122;
27 }
28
29 private static boolean isUpperCase(int code) {
30 return code >= 65 && code <= 90;
31 }
32
33 }
Introducing 

Optional<T>
1 package com.example;
2
3 import java.util.Optional;
4
5 class SafeCharOps {
6
7 static Optional<Character> firstCharacter(
8 String string
9 ) {
10 return (string.length() > 0) ?
11 Optional.of(string.charAt(0)) :
12 Optional.empty();
13 }
14
15 static Optional<Integer> getAlphabetPosition(
16 Character character
17 ) {
18 int code = (int) character;
19
20 return isLowerCase(code) ? Optional.of(code - 96) :
21 isUpperCase(code) ? Optional.of(code - 64) :
22 Optional.empty();
23 }
24
25 private static boolean isLowerCase(int code) {
26 return code >= 97 && code <= 122;
27 }
28
29 private static boolean isUpperCase(int code) {
30 return code >= 65 && code <= 90;
31 }
32
33 }
• optionality of return value
is explicit in type signature
Introducing 

Optional<T>
1 package com.example;
2
3 import java.util.Optional;
4
5 class SafeCharOps {
6
7 static Optional<Character> firstCharacter(
8 String string
9 ) {
10 return (string.length() > 0) ?
11 Optional.of(string.charAt(0)) :
12 Optional.empty();
13 }
14
15 static Optional<Integer> getAlphabetPosition(
16 Character character
17 ) {
18 int code = (int) character;
19
20 return isLowerCase(code) ? Optional.of(code - 96) :
21 isUpperCase(code) ? Optional.of(code - 64) :
22 Optional.empty();
23 }
24
25 private static boolean isLowerCase(int code) {
26 return code >= 97 && code <= 122;
27 }
28
29 private static boolean isUpperCase(int code) {
30 return code >= 65 && code <= 90;
31 }
32
33 }
• optionality of return value
is explicit in type signature
• expressions used where
possible
Introducing 

Optional<T>
Composability
revisited
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
Composability
revisited
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• doesn't compile :(
Composability
revisited
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• doesn't compile :(
• getAlphabetPosition
accepts Character instances
Composability
revisited
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• doesn't compile :(
• getAlphabetPosition
accepts Character instances
• we have
Optional<Character> from

firstCharacter call
Composability
revisited
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.CharacterOps.*;
6
7 public class CharOpsTest {
8
9 @Test
10 public void testComposability() {
11
12 getAlphabetPosition(firstCharacter("cat"));
13
14 getAlphabetPosition(firstCharacter(""));
15
16 }
17
18 }
• doesn't compile :(
• getAlphabetPosition
accepts Character instances
• we have
Optional<Character> from

firstCharacter call
• how to extract value in safe
manner?
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.Optional;
6
7 import static com.example.SafeCharOps.*;
8
9 public class OptionalCharOpsTest {
10
11 @Test
12 public void testOptionalMethods() {
13
14 Optional<Character> firstChar =
15 firstCharacter("cat");
16
17 if (firstChar.isPresent()) {
18
19 Optional<Integer> alphabetPosition =
20 getAlphabetPosition(firstChar.get());
21
22 if (alphabetPosition.isPresent()) {
23 Integer position = alphabetPosition.get();
24
25 // ...
26 }
27
28 }
29
30 }
31
32 }
Imperative 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.Optional;
6
7 import static com.example.SafeCharOps.*;
8
9 public class OptionalCharOpsTest {
10
11 @Test
12 public void testOptionalMethods() {
13
14 Optional<Character> firstChar =
15 firstCharacter("cat");
16
17 if (firstChar.isPresent()) {
18
19 Optional<Integer> alphabetPosition =
20 getAlphabetPosition(firstChar.get());
21
22 if (alphabetPosition.isPresent()) {
23 Integer position = alphabetPosition.get();
24
25 // ...
26 }
27
28 }
29
30 }
31
32 }
• we've gained explicit
information about
optionality
Imperative 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.Optional;
6
7 import static com.example.SafeCharOps.*;
8
9 public class OptionalCharOpsTest {
10
11 @Test
12 public void testOptionalMethods() {
13
14 Optional<Character> firstChar =
15 firstCharacter("cat");
16
17 if (firstChar.isPresent()) {
18
19 Optional<Integer> alphabetPosition =
20 getAlphabetPosition(firstChar.get());
21
22 if (alphabetPosition.isPresent()) {
23 Integer position = alphabetPosition.get();
24
25 // ...
26 }
27
28 }
29
30 }
31
32 }
• we've gained explicit
information about
optionality
• still looks like null checks :(
Imperative 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.Optional;
6
7 import static com.example.SafeCharOps.*;
8
9 public class OptionalCharOpsTest {
10
11 @Test
12 public void testOptionalMethods() {
13
14 Optional<Character> firstChar =
15 firstCharacter("cat");
16
17 if (firstChar.isPresent()) {
18
19 Optional<Integer> alphabetPosition =
20 getAlphabetPosition(firstChar.get());
21
22 if (alphabetPosition.isPresent()) {
23 Integer position = alphabetPosition.get();
24
25 // ...
26 }
27
28 }
29
30 }
31
32 }
• we've gained explicit
information about
optionality
• still looks like null checks :(
• still breaks composability :(
Imperative 

approach
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
• no null checks!
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
• no null checks!
• clean functional
composition
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
• no null checks!
• clean functional
composition
• type safety, IDE helps at
every step as type inference
is easy
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
• no null checks!
• clean functional
composition
• type safety, IDE helps at
every step as type inference
is easy
• easier to refactor
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
• no null checks!
• clean functional
composition
• type safety, IDE helps at
every step as type inference
is easy
• easier to refactor
• elegant & succinct
Functional 

approach
1 package com.example;
2
3 import org.junit.Test;
4
5 import static com.example.SafeCharOps.*;
6
7 public class OptionalCharOpsTest {
8
9 @Test
10 public void testOptionalMethods() {
11
12 firstCharacter("cat")
13 .flatMap(SafeCharOps::getAlphabetPosition)
14 .ifPresent(value -> {
15 assert value == 3;
16 });
17
18 assert !firstCharacter("")
19 .flatMap(SafeCharOps::getAlphabetPosition)
20 .isPresent();
21 }
22
23 }
1 package com.example;
2
3 import java.util.List;
4 import java.util.stream.Collectors;
5
6 class StreamsAndErrors {
7
8 static List<Integer> toNumbers(List<String> strings) {
9 return strings.stream()
10 .map(Integer::parseInt)
11 .collect(Collectors.toList());
12 }
13
14 }
Streams API

revisited: errors
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("1", "2", "3");
15 out.println(StreamsAndErrors.toNumbers(strings));
16 // prints '[1, 2, 3]'
17
18 List<String> itsaTrap = asList("1", "a", "3");
19 out.println(StreamsAndErrors.toNumbers(itsaTrap));
20 // NumberFormatException: For input string: "a"
21 }
22
23 }
1 package com.example;
2
3 import java.util.List;
4 import java.util.stream.Collectors;
5
6 class StreamsAndErrors {
7
8 static List<Integer> toNumbers(List<String> strings) {
9 return strings.stream()
10 .map(Integer::parseInt)
11 .collect(Collectors.toList());
12 }
13
14 }
• generic string to integer
conversion on collection level
Streams API

revisited: errors
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("1", "2", "3");
15 out.println(StreamsAndErrors.toNumbers(strings));
16 // prints '[1, 2, 3]'
17
18 List<String> itsaTrap = asList("1", "a", "3");
19 out.println(StreamsAndErrors.toNumbers(itsaTrap));
20 // NumberFormatException: For input string: "a"
21 }
22
23 }
1 package com.example;
2
3 import java.util.List;
4 import java.util.stream.Collectors;
5
6 class StreamsAndErrors {
7
8 static List<Integer> toNumbers(List<String> strings) {
9 return strings.stream()
10 .map(Integer::parseInt)
11 .collect(Collectors.toList());
12 }
13
14 }
• generic string to integer
conversion on collection level
• type signature tells nothing
about possible of failure
Streams API

revisited: errors
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("1", "2", "3");
15 out.println(StreamsAndErrors.toNumbers(strings));
16 // prints '[1, 2, 3]'
17
18 List<String> itsaTrap = asList("1", "a", "3");
19 out.println(StreamsAndErrors.toNumbers(itsaTrap));
20 // NumberFormatException: For input string: "a"
21 }
22
23 }
1 package com.example;
2
3 import java.util.List;
4 import java.util.stream.Collectors;
5
6 class StreamsAndErrors {
7
8 static List<Integer> toNumbers(List<String> strings) {
9 return strings.stream()
10 .map(Integer::parseInt)
11 .collect(Collectors.toList());
12 }
13
14 }
• generic string to integer
conversion on collection level
• type signature tells nothing
about possible of failure
• programmer knows (let's
hope so) about possibility of
failure and has to deal with it
explicitly
Streams API

revisited: errors
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("1", "2", "3");
15 out.println(StreamsAndErrors.toNumbers(strings));
16 // prints '[1, 2, 3]'
17
18 List<String> itsaTrap = asList("1", "a", "3");
19 out.println(StreamsAndErrors.toNumbers(itsaTrap));
20 // NumberFormatException: For input string: "a"
21 }
22
23 }
1 package com.example;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Optional;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Integer> filterOut(List<String> strings) {
11 return strings.stream()
12 .map(s -> {
13 try {
14 return Integer.parseInt(s);
15 } catch (NumberFormatException nfe) {
16 return null;
17 }
18 })
19 .filter(Objects::nonNull)
20 .collect(Collectors.toList());
21 }
22
23 static Optional<List<Integer>> failOnFirst(
24 List<String> strings
25 ) {
26 try {
27 return Optional.of(
28 strings.stream()
29 .map(Integer::parseInt)
30 .collect(Collectors.toList())
31 );
32 } catch (NumberFormatException nfe) {
33 return Optional.empty();
34 }
35 }
36
37 }
Handling errors 

with try
1 package com.example;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Optional;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Integer> filterOut(List<String> strings) {
11 return strings.stream()
12 .map(s -> {
13 try {
14 return Integer.parseInt(s);
15 } catch (NumberFormatException nfe) {
16 return null;
17 }
18 })
19 .filter(Objects::nonNull)
20 .collect(Collectors.toList());
21 }
22
23 static Optional<List<Integer>> failOnFirst(
24 List<String> strings
25 ) {
26 try {
27 return Optional.of(
28 strings.stream()
29 .map(Integer::parseInt)
30 .collect(Collectors.toList())
31 );
32 } catch (NumberFormatException nfe) {
33 return Optional.empty();
34 }
35 }
36
37 }
• ughh... null again :(
Handling errors 

with try
1 package com.example;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Optional;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Integer> filterOut(List<String> strings) {
11 return strings.stream()
12 .map(s -> {
13 try {
14 return Integer.parseInt(s);
15 } catch (NumberFormatException nfe) {
16 return null;
17 }
18 })
19 .filter(Objects::nonNull)
20 .collect(Collectors.toList());
21 }
22
23 static Optional<List<Integer>> failOnFirst(
24 List<String> strings
25 ) {
26 try {
27 return Optional.of(
28 strings.stream()
29 .map(Integer::parseInt)
30 .collect(Collectors.toList())
31 );
32 } catch (NumberFormatException nfe) {
33 return Optional.empty();
34 }
35 }
36
37 }
• ughh... null again :(
• we have to filter nulls out lest
we create a disaster waiting to
happen
Handling errors 

with try
1 package com.example;
2
3 import java.util.List;
4 import java.util.Objects;
5 import java.util.Optional;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Integer> filterOut(List<String> strings) {
11 return strings.stream()
12 .map(s -> {
13 try {
14 return Integer.parseInt(s);
15 } catch (NumberFormatException nfe) {
16 return null;
17 }
18 })
19 .filter(Objects::nonNull)
20 .collect(Collectors.toList());
21 }
22
23 static Optional<List<Integer>> failOnFirst(
24 List<String> strings
25 ) {
26 try {
27 return Optional.of(
28 strings.stream()
29 .map(Integer::parseInt)
30 .collect(Collectors.toList())
31 );
32 } catch (NumberFormatException nfe) {
33 return Optional.empty();
34 }
35 }
36
37 }
• ughh... null again :(
• we have to filter nulls out lest
we create a disaster waiting to
happen
• using Optional tells caller that
this method might yield value,
but doesn't say anything about
errors that may happen inside
Handling errors 

with try
Handling errors 

with Try
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Try<Integer>> withErrs(List<String> strings) {
11 return strings.stream()
12 .map(s -> Try.of(() -> Integer.parseInt(s)))
13 .collect(Collectors.toList());
14 }
15
16 static Try<List<Integer>> failOnFirst(
17 List<String> strings
18 ) {
19 return Try.of(() -> strings.stream()
20 .map(Integer::parseInt)
21 .collect(Collectors.toList()));
22 }
23
24 }
• type signature explicitly
informs us about the
possibility of error
Handling errors 

with Try
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Try<Integer>> withErrs(List<String> strings) {
11 return strings.stream()
12 .map(s -> Try.of(() -> Integer.parseInt(s)))
13 .collect(Collectors.toList());
14 }
15
16 static Try<List<Integer>> failOnFirst(
17 List<String> strings
18 ) {
19 return Try.of(() -> strings.stream()
20 .map(Integer::parseInt)
21 .collect(Collectors.toList()));
22 }
23
24 }
• type signature explicitly
informs us about the
possibility of error
• exceptions are caught
inside stream or in lambda
wrapping whole stream
processing
Handling errors 

with Try
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndErrors {
9
10 static List<Try<Integer>> withErrs(List<String> strings) {
11 return strings.stream()
12 .map(s -> Try.of(() -> Integer.parseInt(s)))
13 .collect(Collectors.toList());
14 }
15
16 static Try<List<Integer>> failOnFirst(
17 List<String> strings
18 ) {
19 return Try.of(() -> strings.stream()
20 .map(Integer::parseInt)
21 .collect(Collectors.toList()));
22 }
23
24 }
1 package com.example;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndCheckedExceptions {
9
10 private static SimpleDateFormat sdf =
11 new SimpleDateFormat("ddMMyyyy");
12
13 static List<Date> parseAll(List<String> strings) {
14 return strings.stream()
15 .map(sdf::parse) // won't compile!
16 .collect(Collectors.toList());
17 }
18
19 }
Checked exceptions 

& Java 8 Streams:

Rough edges
1 package com.example;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndCheckedExceptions {
9
10 private static SimpleDateFormat sdf =
11 new SimpleDateFormat("ddMMyyyy");
12
13 static List<Date> parseAll(List<String> strings) {
14 return strings.stream()
15 .map(sdf::parse) // won't compile!
16 .collect(Collectors.toList());
17 }
18
19 }
• ParseException is checked,
which breaks lambda
expression
Checked exceptions 

& Java 8 Streams:

Rough edges
1 package com.example;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndCheckedExceptions {
9
10 private static SimpleDateFormat sdf =
11 new SimpleDateFormat("ddMMyyyy");
12
13 static List<Date> parseAll(List<String> strings) {
14 return strings.stream()
15 .map(sdf::parse) // won't compile!
16 .collect(Collectors.toList());
17 }
18
19 }
• ParseException is checked,
which breaks lambda
expression
Checked exceptions 

& Java 8 Streams:

Rough edges
1 package com.example;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.List;
6 import java.util.stream.Collectors;
7
8 class StreamsAndCheckedExceptions {
9
10 private static SimpleDateFormat sdf =
11 new SimpleDateFormat("ddMMyyyy");
12
13 static List<Date> parseAll(List<String> strings) {
14 return strings.stream()
15 .map(sdf::parse) // won't compile!
16 .collect(Collectors.toList());
17 }
18
19 }
• ParseException is checked,
which breaks lambda
expression
• solution using try-catch &
rethrow-as-unchecked block
is ugly and defeats the
purpose of lambdas
Checked exceptions 

& Java 8 Streams:

Rough edges
Checked exceptions 

& Java 8 Streams:

Try to the rescue
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.List;
8 import java.util.stream.Collectors;
9
10 class StreamsAndCheckedExceptions {
11
12 private static SimpleDateFormat sdf =
13 new SimpleDateFormat("ddMMyyyy");
14
15 static List<Try<Date>> parseAll(List<String> strings) {
16 return strings.stream()
17 .map(s -> Try.of(() -> sdf.parse(s)))
18 .collect(Collectors.toList());
19 }
20
21 }
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("10042017", "23");
15 out.println(
16 StreamsAndCheckedExceptions.parseAll(strings)
17 );
18
19 // [
20 // Success(Mon Apr 10 00:00:00 CEST 2017),
21 // Failure(ParseException: Unparseable date: "23")
22 // ]
23 }
24
25 }
• problem of checked
exceptions solved

Checked exceptions 

& Java 8 Streams:

Try to the rescue
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.List;
8 import java.util.stream.Collectors;
9
10 class StreamsAndCheckedExceptions {
11
12 private static SimpleDateFormat sdf =
13 new SimpleDateFormat("ddMMyyyy");
14
15 static List<Try<Date>> parseAll(List<String> strings) {
16 return strings.stream()
17 .map(s -> Try.of(() -> sdf.parse(s)))
18 .collect(Collectors.toList());
19 }
20
21 }
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("10042017", "23");
15 out.println(
16 StreamsAndCheckedExceptions.parseAll(strings)
17 );
18
19 // [
20 // Success(Mon Apr 10 00:00:00 CEST 2017),
21 // Failure(ParseException: Unparseable date: "23")
22 // ]
23 }
24
25 }
• problem of checked
exceptions solved

• we also gained explicit
information of possibility of
failure
Checked exceptions 

& Java 8 Streams:

Try to the rescue
1 package com.example;
2
3 import javaslang.control.Try;
4
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.List;
8 import java.util.stream.Collectors;
9
10 class StreamsAndCheckedExceptions {
11
12 private static SimpleDateFormat sdf =
13 new SimpleDateFormat("ddMMyyyy");
14
15 static List<Try<Date>> parseAll(List<String> strings) {
16 return strings.stream()
17 .map(s -> Try.of(() -> sdf.parse(s)))
18 .collect(Collectors.toList());
19 }
20
21 }
1 package com.example;
2
3 import org.junit.Test;
4
5 import java.util.List;
6
7 import static java.lang.System.out;
8 import static java.util.Arrays.asList;
9
10 public class StreamsTest {
11
12 @Test
13 public void testNumberConversion() {
14 List<String> strings = asList("10042017", "23");
15 out.println(
16 StreamsAndCheckedExceptions.parseAll(strings)
17 );
18
19 // [
20 // Success(Mon Apr 10 00:00:00 CEST 2017),
21 // Failure(ParseException: Unparseable date: "23")
22 // ]
23 }
24
25 }
Case for immutable data
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
• Shared mutable state in concurrent environment requires
synchronisation which is difficult and leads to subtle and 

hard to replicate bugs
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
• Shared mutable state in concurrent environment requires
synchronisation which is difficult and leads to subtle and 

hard to replicate bugs
• Immutable objects and persistent data structures have none of those
problems
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
• Shared mutable state in concurrent environment requires
synchronisation which is difficult and leads to subtle and 

hard to replicate bugs
• Immutable objects and persistent data structures have none of those
problems
• it's trivial to protect invariants once instance is immutable
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
• Shared mutable state in concurrent environment requires
synchronisation which is difficult and leads to subtle and 

hard to replicate bugs
• Immutable objects and persistent data structures have none of those
problems
• it's trivial to protect invariants once instance is immutable
• no need for synchronisation ever
Case for immutable data
• Mutable state makes it significantly harder to reason about a system due
to multiple code branches that can lead to mutation of state
• Shared mutable state in concurrent environment requires
synchronisation which is difficult and leads to subtle and 

hard to replicate bugs
• Immutable objects and persistent data structures have none of those
problems
• it's trivial to protect invariants once instance is immutable
• no need for synchronisation ever
... so how to do this in Java?
Immutable objects

in plain Java
1 package com.example;
2
3 import java.util.Set;
4
5 public class Office {
6
7 private final Set<Room> rooms;
8 private final Set<Employee> employees;
9
10 public Office(Set<Room> rooms, Set<Employee> employees) {
11 this.rooms = rooms;
12 this.employees = employees;
13 }
14
15 public Set<Room> getRooms() {
16 return rooms;
17 }
18
19 public Set<Employee> getEmployees() {
20 return employees;
21 }
22
23 }
Immutable objects

in plain Java
• lots of getter noise1 package com.example;
2
3 import java.util.Set;
4
5 public class Office {
6
7 private final Set<Room> rooms;
8 private final Set<Employee> employees;
9
10 public Office(Set<Room> rooms, Set<Employee> employees) {
11 this.rooms = rooms;
12 this.employees = employees;
13 }
14
15 public Set<Room> getRooms() {
16 return rooms;
17 }
18
19 public Set<Employee> getEmployees() {
20 return employees;
21 }
22
23 }
Immutable objects

in plain Java
• lots of getter noise
• if we want a builder, we have
to create one and make
constructor private
1 package com.example;
2
3 import java.util.Set;
4
5 public class Office {
6
7 private final Set<Room> rooms;
8 private final Set<Employee> employees;
9
10 public Office(Set<Room> rooms, Set<Employee> employees) {
11 this.rooms = rooms;
12 this.employees = employees;
13 }
14
15 public Set<Room> getRooms() {
16 return rooms;
17 }
18
19 public Set<Employee> getEmployees() {
20 return employees;
21 }
22
23 }
Immutable objects

in plain Java
• lots of getter noise
• if we want a builder, we have
to create one and make
constructor private
• optional field is painful as IDE
will cry that fields should
never have type Optional<T>
1 package com.example;
2
3 import java.util.Set;
4
5 public class Office {
6
7 private final Set<Room> rooms;
8 private final Set<Employee> employees;
9
10 public Office(Set<Room> rooms, Set<Employee> employees) {
11 this.rooms = rooms;
12 this.employees = employees;
13 }
14
15 public Set<Room> getRooms() {
16 return rooms;
17 }
18
19 public Set<Employee> getEmployees() {
20 return employees;
21 }
22
23 }
Immutable objects

in plain Java
• lots of getter noise
• if we want a builder, we have
to create one and make
constructor private
• optional field is painful as IDE
will cry that fields should
never have type Optional<T>
• how can we get a copy of
instance with only one field
modified?
1 package com.example;
2
3 import java.util.Set;
4
5 public class Office {
6
7 private final Set<Room> rooms;
8 private final Set<Employee> employees;
9
10 public Office(Set<Room> rooms, Set<Employee> employees) {
11 this.rooms = rooms;
12 this.employees = employees;
13 }
14
15 public Set<Room> getRooms() {
16 return rooms;
17 }
18
19 public Set<Employee> getEmployees() {
20 return employees;
21 }
22
23 }
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
• highly customisable code
generation
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
• highly customisable code
generation
• handles Optional<T> values
correctly
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
• highly customisable code
generation
• handles Optional<T> values
correctly
• handles default values
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
• highly customisable code
generation
• handles Optional<T> values
correctly
• handles default values
• Jackson / Gson integration out-
of-the-box
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
• that's all!
• highly customisable code
generation
• handles Optional<T> values
correctly
• handles default values
• Jackson / Gson integration out-
of-the-box
• provides with* methods
allowing painless modification
of immutable instances
Enter Immutables
1 package com.example;
2
3 import javaslang.collection.Set;
4 import org.immutables.value.Value;
5
6 @Value.Immutable
7 @Value.Style(typeImmutable = "*")
8 abstract class AbstractOffice {
9 abstract Set<Room> rooms();
10
11 abstract Set<Employee> employees();
12
13 abstract boolean open();
14 }
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
• named factory method can be
generated (of by default)
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
• named factory method can be
generated (of by default)
• builder class is generated by
default
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
• named factory method can be
generated (of by default)
• builder class is generated by
default
• toString, hashCode and equals
are generated using best practice
methods
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
• named factory method can be
generated (of by default)
• builder class is generated by
default
• toString, hashCode and equals
are generated using best practice
methods
• with(field) methods make
obtaining modified instances a
breeze!
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
• named factory method can be
generated (of by default)
• builder class is generated by
default
• toString, hashCode and equals
are generated using best practice
methods
• with(field) methods make
obtaining modified instances a
breeze!
• nulls are not allowed by default,
so fail early rule is enforced
Immutables
in action
1 package com.example;
2
3 import javaslang.collection.HashSet;
4 import org.junit.Test;
5
6 public class OfficeTest {
7
8 @Test
9 public void muchSafeSuchImmutableVeryWow() {
10
11 HashSet<Employee> employees = HashSet.of(
12 Employee.of("Boss")
13 );
14
15 HashSet<Room> rooms = HashSet.of(
16 Room.of("Boss' office")
17 );
18
19 Office office = Office.builder()
20 .employees(employees)
21 .rooms(rooms)
22 .open(true)
23 .build();
24
25 System.out.println(office);
26 // Office{
27 // rooms=HashSet(Room{name=Boss' office}),
28 // employees=HashSet(Employee{name=Boss}),
29 // open=true}
30
31 Office officeWithoutEmployees = office
32 .withEmployees(HashSet.empty())
33 .withOpen(false);
34
35 System.out.println(officeWithoutEmployees);
36 // Office{
37 // rooms=HashSet(Room{name=Boss' office}),
38 // employees=HashSet(),
39 // open=false}
40 }
41 }
About that 

javaslang.collection.HashSet
About that 

javaslang.collection.HashSet
• Javaslang provides immutable, persistent, purely functional
collections that match Java Collections
About that 

javaslang.collection.HashSet
• Javaslang provides immutable, persistent, purely functional
collections that match Java Collections
• Immutable, so every operation returns a new instance
About that 

javaslang.collection.HashSet
• Javaslang provides immutable, persistent, purely functional
collections that match Java Collections
• Immutable, so every operation returns a new instance
• Persistent, so creation of new instance means that data is
shared between instances of collection and only the reference
to modified element is replaced
About that 

javaslang.collection.HashSet
• Javaslang provides immutable, persistent, purely functional
collections that match Java Collections
• Immutable, so every operation returns a new instance
• Persistent, so creation of new instance means that data is
shared between instances of collection and only the reference
to modified element is replaced
• Functional, so all operations are referentially transparent

(at least as long as values stored in collection are immutable!)
Javaslang 

Collections APIs
• classic, imperative
approach with
StringBuilder: for loop
and append calls
Javaslang 

Collections APIs
1 String join(String... words) {
2 StringBuilder builder = new StringBuilder();
3 for(String s : words) {
4 if (builder.length() > 0) {
5 builder.append(", ");
6 }
7 builder.append(s);
8 }
9 return builder.toString();
10 }
• classic, imperative
approach with
StringBuilder: for loop
and append calls
Javaslang 

Collections APIs
1 String join(String... words) {
2 StringBuilder builder = new StringBuilder();
3 for(String s : words) {
4 if (builder.length() > 0) {
5 builder.append(", ");
6 }
7 builder.append(s);
8 }
9 return builder.toString();
10 }
• classic, imperative
approach with
StringBuilder: for loop
and append calls
• declarative use of List
methods and fold
(reduce to accumulator
value)
Javaslang 

Collections APIs
1 String join(String... words) {
2 StringBuilder builder = new StringBuilder();
3 for(String s : words) {
4 if (builder.length() > 0) {
5 builder.append(", ");
6 }
7 builder.append(s);
8 }
9 return builder.toString();
10 }
1 String join(String... words) {
2 return List.of(words)
3 .intersperse(", ")
4 .fold("", String::concat);
5 }
• classic, imperative
approach with
StringBuilder: for loop
and append calls
• declarative use of List
methods and fold
(reduce to accumulator
value)
Javaslang 

Collections APIs
1 String join(String... words) {
2 StringBuilder builder = new StringBuilder();
3 for(String s : words) {
4 if (builder.length() > 0) {
5 builder.append(", ");
6 }
7 builder.append(s);
8 }
9 return builder.toString();
10 }
1 String join(String... words) {
2 return List.of(words)
3 .intersperse(", ")
4 .fold("", String::concat);
5 }
• classic, imperative
approach with
StringBuilder: for loop
and append calls
• declarative use of List
methods and fold
(reduce to accumulator
value)
• a helper method!
Javaslang 

Collections APIs
1 String join(String... words) {
2 StringBuilder builder = new StringBuilder();
3 for(String s : words) {
4 if (builder.length() > 0) {
5 builder.append(", ");
6 }
7 builder.append(s);
8 }
9 return builder.toString();
10 }
1 String join(String... words) {
2 return List.of(words)
3 .intersperse(", ")
4 .fold("", String::concat);
5 }
1 List.of(words).mkString(", ");
• classic, imperative
approach with
StringBuilder: for loop
and append calls
• declarative use of List
methods and fold
(reduce to accumulator
value)
• a helper method!
Javaslang 

Collections APIs
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.HashSet;
6 import javaslang.collection.Map;
7 import javaslang.collection.Set;
8
9 public class PhoneNumberData {
10
11 public static final Set<String> phoneNumbers =
12 HashSet.of(
13 "+48413422345",
14 "413572456",
15 "+48413456990",
16 "48225697246",
17 "+48224914634",
18 "48126434972",
19 "+48128275242"
20 );
21
22 public static final Map<String, String> areas =
23 HashMap.ofEntries(
24 Tuple.of("41", "Kielce"),
25 Tuple.of("22", "Warszawa"),
26 Tuple.of("12", "Kraków")
27 );
28
29 }
A more complex 

example...
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.HashSet;
6 import javaslang.collection.Map;
7 import javaslang.collection.Set;
8
9 public class PhoneNumberData {
10
11 public static final Set<String> phoneNumbers =
12 HashSet.of(
13 "+48413422345",
14 "413572456",
15 "+48413456990",
16 "48225697246",
17 "+48224914634",
18 "48126434972",
19 "+48128275242"
20 );
21
22 public static final Map<String, String> areas =
23 HashMap.ofEntries(
24 Tuple.of("41", "Kielce"),
25 Tuple.of("22", "Warszawa"),
26 Tuple.of("12", "Kraków")
27 );
28
29 }
• phoneNumbers: phone
numbers in different
formats
A more complex 

example...
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.HashSet;
6 import javaslang.collection.Map;
7 import javaslang.collection.Set;
8
9 public class PhoneNumberData {
10
11 public static final Set<String> phoneNumbers =
12 HashSet.of(
13 "+48413422345",
14 "413572456",
15 "+48413456990",
16 "48225697246",
17 "+48224914634",
18 "48126434972",
19 "+48128275242"
20 );
21
22 public static final Map<String, String> areas =
23 HashMap.ofEntries(
24 Tuple.of("41", "Kielce"),
25 Tuple.of("22", "Warszawa"),
26 Tuple.of("12", "Kraków")
27 );
28
29 }
• phoneNumbers: phone
numbers in different
formats
• areas: maps prefixes to area
names
A more complex 

example...
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.HashSet;
6 import javaslang.collection.Map;
7 import javaslang.collection.Set;
8
9 public class PhoneNumberData {
10
11 public static final Set<String> phoneNumbers =
12 HashSet.of(
13 "+48413422345",
14 "413572456",
15 "+48413456990",
16 "48225697246",
17 "+48224914634",
18 "48126434972",
19 "+48128275242"
20 );
21
22 public static final Map<String, String> areas =
23 HashMap.ofEntries(
24 Tuple.of("41", "Kielce"),
25 Tuple.of("22", "Warszawa"),
26 Tuple.of("12", "Kraków")
27 );
28
29 }
• phoneNumbers: phone
numbers in different
formats
• areas: maps prefixes to area
names
• task: group numbers by
area name
A more complex 

example...
Processing!1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
• strip international code from
processed tuple entry, don't do
anything to original
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
• strip international code from
processed tuple entry, don't do
anything to original
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
• strip international code from
processed tuple entry, don't do
anything to original
• group tuples by area code
obtained from processed tuple
entry
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
• strip international code from
processed tuple entry, don't do
anything to original
• group tuples by area code
obtained from processed tuple
entry
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Processing!
• filter out numbers that are too
short
• we need to have original number
and still process it - Tuples!
• strip international code from
processed tuple entry, don't do
anything to original
• group tuples by area code
obtained from processed tuple
entry
• map keys and values to either
area name and set of original
phone numbers
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import javaslang.collection.HashMap;
6 import javaslang.collection.HashSet;
7 import javaslang.collection.Map;
8 import javaslang.collection.Set;
9 import org.junit.Test;
10
11 import static java.util.function.Function.identity;
12 import static com.example.PhoneNumberData.*;
13
14 public class GroupNumbersTest {
15
16 @Test
17 public void processNumbers() {
18 Map<String, Set<String>> map = phoneNumbers
19 .filter(num -> num.length() >= 9)
20 .map(number -> Tuple.of(number, number))
21 .map(tuple ->
22 tuple.map(
23 num -> num.replaceFirst("^+?48", ""),
24 identity()
25 )
26 )
27 .groupBy(tuple -> tuple._1().substring(0, 2))
28 .bimap(
29 key -> areas.get(key).getOrElse("Nieznany"),
30 value -> value.map(Tuple2::_2)
31 );
32
33 System.out.println(map);
34 }
35
36 }
Results:
Results:
HashMap(

(Kielce, HashSet(+48413456990, +48413422345, 413572456)), 

(Kraków, HashSet(+48128275242, 48126434972)), 

(Warszawa, HashSet(+48224914634, 48225697246))

)
Results:
HashMap(

(Kielce, HashSet(+48413456990, +48413422345, 413572456)), 

(Kraków, HashSet(+48128275242, 48126434972)), 

(Warszawa, HashSet(+48224914634, 48225697246))

)
... neat!

Results:
HashMap(

(Kielce, HashSet(+48413456990, +48413422345, 413572456)), 

(Kraków, HashSet(+48128275242, 48126434972)), 

(Warszawa, HashSet(+48224914634, 48225697246))

)
... neat!

But what if that was an infinite stream of phone numbers?
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.Map;
6 import rx.Observable;
7
8 public class StreamingPhoneNumberData {
9
10 public static final Observable<String> phoneNumbers =
11 Observable.from(new String[]{
12 "+48413422345",
13 "413572456",
14 "+48413456990",
15 "48225697246",
16 "+48224914634",
17 "48126434972",
18 "+48128275242"
19 });
20
21 public static final Map<String, String> areas =
22 HashMap.ofEntries(
23 Tuple.of("41", "Kielce"),
24 Tuple.of("22", "Warszawa"),
25 Tuple.of("12", "Kraków")
26 );
27
28 }
Event streams 

with RxJava
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.Map;
6 import rx.Observable;
7
8 public class StreamingPhoneNumberData {
9
10 public static final Observable<String> phoneNumbers =
11 Observable.from(new String[]{
12 "+48413422345",
13 "413572456",
14 "+48413456990",
15 "48225697246",
16 "+48224914634",
17 "48126434972",
18 "+48128275242"
19 });
20
21 public static final Map<String, String> areas =
22 HashMap.ofEntries(
23 Tuple.of("41", "Kielce"),
24 Tuple.of("22", "Warszawa"),
25 Tuple.of("12", "Kraków")
26 );
27
28 }
Event streams 

with RxJava
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.collection.HashMap;
5 import javaslang.collection.Map;
6 import rx.Observable;
7
8 public class StreamingPhoneNumberData {
9
10 public static final Observable<String> phoneNumbers =
11 Observable.from(new String[]{
12 "+48413422345",
13 "413572456",
14 "+48413456990",
15 "48225697246",
16 "+48224914634",
17 "48126434972",
18 "+48128275242"
19 });
20
21 public static final Map<String, String> areas =
22 HashMap.ofEntries(
23 Tuple.of("41", "Kielce"),
24 Tuple.of("22", "Warszawa"),
25 Tuple.of("12", "Kraków")
26 );
27
28 }
Event streams 

with RxJava
• Observable<T> is 

a 0 .. n collection of
events (potentially
infinite!)
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import org.junit.Test;
6 import rx.observables.GroupedObservable;
7
8 import static com.example.PhoneNumberData.areas;
9 import static com.example.StreamingData.phoneNumbers;
10 import static java.lang.System.out;
11 import static java.util.function.Function.identity;
12
13 public class RxGroupPhoneNumbersTest {
14
15 @Test
16 public void processNumbers() {
17 phoneNumbers
18 .filter(num -> num.length() >= 9)
19 .map(number -> Tuple.of(number, number))
20 .map(tuple ->
21 tuple.map(
22 num -> num.replaceFirst("^+?48", ""),
23 identity()
24 )
25 )
26 .groupBy(tuple -> tuple._1().substring(0, 2))
27 .map(grouped ->
28 GroupedObservable.from(
29 areas.get(grouped.getKey())
30 .getOrElse("Unknown"),
31 grouped.map(Tuple2::_2)
32 )
33 )
34 .forEach(grouped -> grouped.forEach(number ->
35 out.println(
36 grouped.getKey() + ": " + number
37 )
38 )
39 );
40 }
41
42 }
Event streams 

with RxJava: 

reuse your lambdas!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import org.junit.Test;
6 import rx.observables.GroupedObservable;
7
8 import static com.example.PhoneNumberData.areas;
9 import static com.example.StreamingData.phoneNumbers;
10 import static java.lang.System.out;
11 import static java.util.function.Function.identity;
12
13 public class RxGroupPhoneNumbersTest {
14
15 @Test
16 public void processNumbers() {
17 phoneNumbers
18 .filter(num -> num.length() >= 9)
19 .map(number -> Tuple.of(number, number))
20 .map(tuple ->
21 tuple.map(
22 num -> num.replaceFirst("^+?48", ""),
23 identity()
24 )
25 )
26 .groupBy(tuple -> tuple._1().substring(0, 2))
27 .map(grouped ->
28 GroupedObservable.from(
29 areas.get(grouped.getKey())
30 .getOrElse("Unknown"),
31 grouped.map(Tuple2::_2)
32 )
33 )
34 .forEach(grouped -> grouped.forEach(number ->
35 out.println(
36 grouped.getKey() + ": " + number
37 )
38 )
39 );
40 }
41
42 }
Event streams 

with RxJava: 

reuse your lambdas!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import org.junit.Test;
6 import rx.observables.GroupedObservable;
7
8 import static com.example.PhoneNumberData.areas;
9 import static com.example.StreamingData.phoneNumbers;
10 import static java.lang.System.out;
11 import static java.util.function.Function.identity;
12
13 public class RxGroupPhoneNumbersTest {
14
15 @Test
16 public void processNumbers() {
17 phoneNumbers
18 .filter(num -> num.length() >= 9)
19 .map(number -> Tuple.of(number, number))
20 .map(tuple ->
21 tuple.map(
22 num -> num.replaceFirst("^+?48", ""),
23 identity()
24 )
25 )
26 .groupBy(tuple -> tuple._1().substring(0, 2))
27 .map(grouped ->
28 GroupedObservable.from(
29 areas.get(grouped.getKey())
30 .getOrElse("Unknown"),
31 grouped.map(Tuple2::_2)
32 )
33 )
34 .forEach(grouped -> grouped.forEach(number ->
35 out.println(
36 grouped.getKey() + ": " + number
37 )
38 )
39 );
40 }
41
42 }
Event streams 

with RxJava: 

reuse your lambdas!
• highlighted code is the same
as code used on Javaslang
collection!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import org.junit.Test;
6 import rx.observables.GroupedObservable;
7
8 import static com.example.PhoneNumberData.areas;
9 import static com.example.StreamingData.phoneNumbers;
10 import static java.lang.System.out;
11 import static java.util.function.Function.identity;
12
13 public class RxGroupPhoneNumbersTest {
14
15 @Test
16 public void processNumbers() {
17 phoneNumbers
18 .filter(num -> num.length() >= 9)
19 .map(number -> Tuple.of(number, number))
20 .map(tuple ->
21 tuple.map(
22 num -> num.replaceFirst("^+?48", ""),
23 identity()
24 )
25 )
26 .groupBy(tuple -> tuple._1().substring(0, 2))
27 .map(grouped ->
28 GroupedObservable.from(
29 areas.get(grouped.getKey())
30 .getOrElse("Unknown"),
31 grouped.map(Tuple2::_2)
32 )
33 )
34 .forEach(grouped -> grouped.forEach(number ->
35 out.println(
36 grouped.getKey() + ": " + number
37 )
38 )
39 );
40 }
41
42 }
Event streams 

with RxJava: 

reuse your lambdas!
• highlighted code is the same
as code used on Javaslang
collection!
• we are operating on
potentially infinite stream, so
groupBy returns Observable
of GroupedObservables - a
stream of streams of values
grouped by key!
1 package com.example;
2
3 import javaslang.Tuple;
4 import javaslang.Tuple2;
5 import org.junit.Test;
6 import rx.observables.GroupedObservable;
7
8 import static com.example.PhoneNumberData.areas;
9 import static com.example.StreamingData.phoneNumbers;
10 import static java.lang.System.out;
11 import static java.util.function.Function.identity;
12
13 public class RxGroupPhoneNumbersTest {
14
15 @Test
16 public void processNumbers() {
17 phoneNumbers
18 .filter(num -> num.length() >= 9)
19 .map(number -> Tuple.of(number, number))
20 .map(tuple ->
21 tuple.map(
22 num -> num.replaceFirst("^+?48", ""),
23 identity()
24 )
25 )
26 .groupBy(tuple -> tuple._1().substring(0, 2))
27 .map(grouped ->
28 GroupedObservable.from(
29 areas.get(grouped.getKey())
30 .getOrElse("Unknown"),
31 grouped.map(Tuple2::_2)
32 )
33 )
34 .forEach(grouped -> grouped.forEach(number ->
35 out.println(
36 grouped.getKey() + ": " + number
37 )
38 )
39 );
40 }
41
42 }
Event streams 

with RxJava: 

reuse your lambdas!
• highlighted code is the same
as code used on Javaslang
collection!
• we are operating on
potentially infinite stream, so
groupBy returns Observable
of GroupedObservables - a
stream of streams of values
grouped by key!
Use cases of

Reactive Extensions
Use cases of

Reactive Extensions
• Streams of events
Use cases of

Reactive Extensions
• Streams of events
• Parallel processing
Use cases of

Reactive Extensions
• Streams of events
• Parallel processing
• Asynchronous programming
Use cases of

Reactive Extensions
• Streams of events
• Parallel processing
• Asynchronous programming
• Bonus: functional error handling
Use cases of

Reactive Extensions
• Streams of events
• Parallel processing
• Asynchronous programming
• Bonus: functional error handling
• Bonus: reactive streams specification
Functional Programming in
Java: not needed, right?
Functional Programming in
Java: not needed, right?
• Microservices need linear scalability on instance level,
which is hard to achieve using thread-per-request
model, asynchronous frameworks offer this 

out-of-the-box
Functional Programming in
Java: not needed, right?
• Microservices need linear scalability on instance level,
which is hard to achieve using thread-per-request
model, asynchronous frameworks offer this 

out-of-the-box
• Reactive, event-driven programming model has already
been included into latest Java version - reactive streams
interfaces made it to JDK9!
Also - Spring 5:
1 @GetMapping("/accounts/{id}/alerts")
2 public Flux<Alert> getAccountAlerts(@PathVariable Long id) {
3
4 return this.repository.getAccount(id)
5 .flatMap(account ->
6 this.webClient
7 .perform(get("/alerts/{key}", account.getKey()))
8 .extract(bodyStream(Alert.class))
9 );
10 }
And Vert.x:
1 server.requestStream()
2 .toObservable()
3 .subscribe(request ->
4 request.toObservable()
5 .lift(RxHelper.unmarshaller(MyPojo.class))
6 .map(Marshaller::toMongoDocument)
7 .flatMap(jsonObject -> mongo.insertObservable(MY_POJOS, jsonObject))
8 .subscribe(
9 () -> request.response()
10 .setStatusCode(200)
11 .end(),
12 err -> request.response()
13 .setStatusCode(500)
14 .end()
15 )
16 );
Thanks for listening!

More Related Content

What's hot

Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
Van Huong
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
LivePerson
 
Java best practices
Java best practicesJava best practices
Java best practices
Ray Toal
 
Java 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsJava 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & Streams
NewCircle Training
 
New Features in JDK 8
New Features in JDK 8New Features in JDK 8
New Features in JDK 8
Martin Toshev
 
Functional programming principles and Java 8
Functional programming principles and Java 8Functional programming principles and Java 8
Functional programming principles and Java 8
Dragos Balan
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
NexThoughts Technologies
 
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and StreamsIntroduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Emiel Paasschens
 
Cracking OCA and OCP Java 8 Exams
Cracking OCA and OCP Java 8 ExamsCracking OCA and OCP Java 8 Exams
Cracking OCA and OCP Java 8 Exams
Ganesh Samarthyam
 
java 8 new features
java 8 new features java 8 new features
java 8 new features
Rohit Verma
 
Java8
Java8Java8
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
Jérôme Rocheteau
 
Java 8 Lambda and Streams
Java 8 Lambda and StreamsJava 8 Lambda and Streams
Java 8 Lambda and Streams
Venkata Naga Ravi
 
Core java
Core javaCore java
Core java
kasaragaddaslide
 
OCP Java (OCPJP) 8 Exam Quick Reference Card
OCP Java (OCPJP) 8 Exam Quick Reference CardOCP Java (OCPJP) 8 Exam Quick Reference Card
OCP Java (OCPJP) 8 Exam Quick Reference Card
Hari kiran G
 
Lambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian GoetzLambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian Goetz
JAX London
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
Deniz Oguz
 
Java8 features
Java8 featuresJava8 features
Java8 features
Elias Hasnat
 

What's hot (18)

Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Java best practices
Java best practicesJava best practices
Java best practices
 
Java 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsJava 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & Streams
 
New Features in JDK 8
New Features in JDK 8New Features in JDK 8
New Features in JDK 8
 
Functional programming principles and Java 8
Functional programming principles and Java 8Functional programming principles and Java 8
Functional programming principles and Java 8
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
 
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and StreamsIntroduction of Java 8 with emphasis on Lambda Expressions and Streams
Introduction of Java 8 with emphasis on Lambda Expressions and Streams
 
Cracking OCA and OCP Java 8 Exams
Cracking OCA and OCP Java 8 ExamsCracking OCA and OCP Java 8 Exams
Cracking OCA and OCP Java 8 Exams
 
java 8 new features
java 8 new features java 8 new features
java 8 new features
 
Java8
Java8Java8
Java8
 
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
How Green are Java Best Coding Practices? - GreenDays @ Rennes - 2014-07-01
 
Java 8 Lambda and Streams
Java 8 Lambda and StreamsJava 8 Lambda and Streams
Java 8 Lambda and Streams
 
Core java
Core javaCore java
Core java
 
OCP Java (OCPJP) 8 Exam Quick Reference Card
OCP Java (OCPJP) 8 Exam Quick Reference CardOCP Java (OCPJP) 8 Exam Quick Reference Card
OCP Java (OCPJP) 8 Exam Quick Reference Card
 
Lambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian GoetzLambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian Goetz
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
 
Java8 features
Java8 featuresJava8 features
Java8 features
 

Viewers also liked

Οικονομικές Σχολές & Τμήματα
Οικονομικές Σχολές & ΤμήματαΟικονομικές Σχολές & Τμήματα
Οικονομικές Σχολές & Τμήματα
Xristina Drosou
 
Cassavabase workshop ibadan March17
Cassavabase workshop ibadan March17Cassavabase workshop ibadan March17
Cassavabase workshop ibadan March17
solgenomics
 
Java 8 ​and ​Best Practices
 Java 8 ​and ​Best Practices Java 8 ​and ​Best Practices
Java 8 ​and ​Best Practices
WSO2
 
Corynebacterium diphtheriae
Corynebacterium diphtheriaeCorynebacterium diphtheriae
Corynebacterium diphtheriae
Microbiology
 
Antimicrobial chemotherapy
Antimicrobial   chemotherapyAntimicrobial   chemotherapy
Antimicrobial chemotherapy
Microbiology
 
Pseudomonas
PseudomonasPseudomonas
Pseudomonas
Microbiology
 
Neisseria
NeisseriaNeisseria
Neisseria
Microbiology
 
Neisseria
NeisseriaNeisseria
Neisseria
Microbiology
 
Xana
XanaXana
Xana
isarevi
 
правильное питание
правильное питаниеправильное питание
правильное питание
virtualtaganrog
 
How to generate customized java 8 code from your database
How to generate customized java 8 code from your databaseHow to generate customized java 8 code from your database
How to generate customized java 8 code from your database
Speedment, Inc.
 
Presentation on java
Presentation  on  javaPresentation  on  java
Presentation on java
shashi shekhar
 
Introduction to Java programming - Java tutorial for beginners to teach Java ...
Introduction to Java programming - Java tutorial for beginners to teach Java ...Introduction to Java programming - Java tutorial for beginners to teach Java ...
Introduction to Java programming - Java tutorial for beginners to teach Java ...
Duckademy IT courses
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出
wang hongjiang
 
JavaScript Frameworks and Java EE – A Great Match
JavaScript Frameworks and Java EE – A Great MatchJavaScript Frameworks and Java EE – A Great Match
JavaScript Frameworks and Java EE – A Great Match
Reza Rahman
 
Should we really be worried of earth infrastructure complaints over web
Should we really be worried of earth infrastructure complaints over webShould we really be worried of earth infrastructure complaints over web
Should we really be worried of earth infrastructure complaints over web
Earth Infra
 

Viewers also liked (16)

Οικονομικές Σχολές & Τμήματα
Οικονομικές Σχολές & ΤμήματαΟικονομικές Σχολές & Τμήματα
Οικονομικές Σχολές & Τμήματα
 
Cassavabase workshop ibadan March17
Cassavabase workshop ibadan March17Cassavabase workshop ibadan March17
Cassavabase workshop ibadan March17
 
Java 8 ​and ​Best Practices
 Java 8 ​and ​Best Practices Java 8 ​and ​Best Practices
Java 8 ​and ​Best Practices
 
Corynebacterium diphtheriae
Corynebacterium diphtheriaeCorynebacterium diphtheriae
Corynebacterium diphtheriae
 
Antimicrobial chemotherapy
Antimicrobial   chemotherapyAntimicrobial   chemotherapy
Antimicrobial chemotherapy
 
Pseudomonas
PseudomonasPseudomonas
Pseudomonas
 
Neisseria
NeisseriaNeisseria
Neisseria
 
Neisseria
NeisseriaNeisseria
Neisseria
 
Xana
XanaXana
Xana
 
правильное питание
правильное питаниеправильное питание
правильное питание
 
How to generate customized java 8 code from your database
How to generate customized java 8 code from your databaseHow to generate customized java 8 code from your database
How to generate customized java 8 code from your database
 
Presentation on java
Presentation  on  javaPresentation  on  java
Presentation on java
 
Introduction to Java programming - Java tutorial for beginners to teach Java ...
Introduction to Java programming - Java tutorial for beginners to teach Java ...Introduction to Java programming - Java tutorial for beginners to teach Java ...
Introduction to Java programming - Java tutorial for beginners to teach Java ...
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出
 
JavaScript Frameworks and Java EE – A Great Match
JavaScript Frameworks and Java EE – A Great MatchJavaScript Frameworks and Java EE – A Great Match
JavaScript Frameworks and Java EE – A Great Match
 
Should we really be worried of earth infrastructure complaints over web
Should we really be worried of earth infrastructure complaints over webShould we really be worried of earth infrastructure complaints over web
Should we really be worried of earth infrastructure complaints over web
 

Similar to Functional Java 8 - Introduction

Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
Talha Ocakçı
 
Programming in java basics
Programming in java  basicsProgramming in java  basics
Programming in java basics
LovelitJose
 
Beyond PITS, Functional Principles for Software Architecture
Beyond PITS, Functional Principles for Software ArchitectureBeyond PITS, Functional Principles for Software Architecture
Beyond PITS, Functional Principles for Software Architecture
Jayaram Sankaranarayanan
 
Core Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika TutorialsCore Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika Tutorials
Mahika Tutorials
 
Java
Java Java
How Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran MizrahiHow Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran Mizrahi
Ran Mizrahi
 
Introduction to scala for a c programmer
Introduction to scala for a c programmerIntroduction to scala for a c programmer
Introduction to scala for a c programmerGirish Kumar A L
 
Introduction to Scala language
Introduction to Scala languageIntroduction to Scala language
Introduction to Scala language
Aaqib Pervaiz
 
Not your father's tests
Not your father's testsNot your father's tests
Not your father's tests
Sean P. Floyd
 
Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?
Mario Camou Riveroll
 
Introduction to Kotlin for Android developers
Introduction to Kotlin for Android developersIntroduction to Kotlin for Android developers
Introduction to Kotlin for Android developers
Mohamed Wael
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax Trees
Jamund Ferguson
 
Building Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with ScalaBuilding Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with ScalaWO Community
 
Synapseindia reviews.odp.
Synapseindia reviews.odp.Synapseindia reviews.odp.
Synapseindia reviews.odp.
Tarunsingh198
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
ArnaldoCanelas
 
Java_Tutorial_Introduction_to_Core_java.ppt
Java_Tutorial_Introduction_to_Core_java.pptJava_Tutorial_Introduction_to_Core_java.ppt
Java_Tutorial_Introduction_to_Core_java.ppt
Govind Samleti
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1Todor Kolev
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1Todor Kolev
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1Todor Kolev
 

Similar to Functional Java 8 - Introduction (20)

Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Programming in java basics
Programming in java  basicsProgramming in java  basics
Programming in java basics
 
Beyond PITS, Functional Principles for Software Architecture
Beyond PITS, Functional Principles for Software ArchitectureBeyond PITS, Functional Principles for Software Architecture
Beyond PITS, Functional Principles for Software Architecture
 
Core Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika TutorialsCore Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika Tutorials
 
Java
Java Java
Java
 
How Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran MizrahiHow Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran Mizrahi
 
Introduction to scala for a c programmer
Introduction to scala for a c programmerIntroduction to scala for a c programmer
Introduction to scala for a c programmer
 
Introduction to Scala language
Introduction to Scala languageIntroduction to Scala language
Introduction to Scala language
 
Not your father's tests
Not your father's testsNot your father's tests
Not your father's tests
 
Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?Static or Dynamic Typing? Why not both?
Static or Dynamic Typing? Why not both?
 
Introduction to Kotlin for Android developers
Introduction to Kotlin for Android developersIntroduction to Kotlin for Android developers
Introduction to Kotlin for Android developers
 
Don't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax TreesDon't Be Afraid of Abstract Syntax Trees
Don't Be Afraid of Abstract Syntax Trees
 
Building Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with ScalaBuilding Concurrent WebObjects applications with Scala
Building Concurrent WebObjects applications with Scala
 
Synapseindia reviews.odp.
Synapseindia reviews.odp.Synapseindia reviews.odp.
Synapseindia reviews.odp.
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
 
Java_Tutorial_Introduction_to_Core_java.ppt
Java_Tutorial_Introduction_to_Core_java.pptJava_Tutorial_Introduction_to_Core_java.ppt
Java_Tutorial_Introduction_to_Core_java.ppt
 
Scala ntnu
Scala ntnuScala ntnu
Scala ntnu
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1
 
Java findamentals1
Java findamentals1Java findamentals1
Java findamentals1
 

Recently uploaded

State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 

Recently uploaded (20)

State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 

Functional Java 8 - Introduction

  • 3. What is functional programming? • usage of pure functions
  • 4. What is functional programming? • usage of pure functions • expressions instead of statements
  • 5. What is functional programming? • usage of pure functions • expressions instead of statements • widespread immutability
  • 6. What is functional programming? • usage of pure functions • expressions instead of statements • widespread immutability • referential transparency
  • 7. What is functional programming? • usage of pure functions • expressions instead of statements • widespread immutability • referential transparency • lazy evaluation
  • 8. What is functional programming? • usage of pure functions • expressions instead of statements • widespread immutability • referential transparency • lazy evaluation ... and functional idioms!
  • 10. What's the gain? • More predictable execution (same arguments always yield the same results)
  • 11. What's the gain? • More predictable execution (same arguments always yield the same results) • Easier to reason about
  • 12. What's the gain? • More predictable execution (same arguments always yield the same results) • Easier to reason about • Easier to enforce strict type correctness
  • 13. What's the gain? • More predictable execution (same arguments always yield the same results) • Easier to reason about • Easier to enforce strict type correctness • more precise checks in compile time
  • 14. What's the gain? • More predictable execution (same arguments always yield the same results) • Easier to reason about • Easier to enforce strict type correctness • more precise checks in compile time • less bugs in runtime
  • 15. How does this relate to Java at all?
  • 16. How does this relate to Java at all? java.lang.NullPointerException at org.springsource.loaded.agent.SpringLoadedPreProcessor.tryToEnsureSystemClassesInitialized(SpringLoadedPreProcessor.java:362) at org.springsource.loaded.agent.SpringLoadedPreProcessor.preProcess(SpringLoadedPreProcessor.java:128) at org.springsource.loaded.agent.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:102) at sun.instrument.TransformerManager.transform(TransformerManager.java:188) at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:800) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818) at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:800) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818) at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526) at org.springframework.util.ClassUtils.forName(ClassUtils.java:265) at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:419) at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1299) at org.springframework.beans.factory.support.AbstractBeanFactory.access$000(AbstractBeanFactory.java:109) at org.springframework.beans.factory.support.AbstractBeanFactory$4.run(AbstractBeanFactory.java:1265) at org.springframework.beans.factory.support.AbstractBeanFactory$4.run(AbstractBeanFactory.java:1263) at java.security.AccessController.doPrivileged(Native Method) at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1263) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:575) at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1347) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:358) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:327) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:437) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:626) at com.xxx.core.web.WebApplicationContext.invokeBeanFactoryPostProcessors(WebApplicationContext.java) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461) at com.xxx.core.web.WebApplicationContext.refresh(WebApplicationContext.java) ...
  • 18. Most common errors in Java • Takipi monitoring service analysed error logs of over 1k enterprise apps
  • 19. Most common errors in Java • Takipi monitoring service analysed error logs of over 1k enterprise apps • 29,965,285 exceptions over 30 days
  • 20. Most common errors in Java • Takipi monitoring service analysed error logs of over 1k enterprise apps • 29,965,285 exceptions over 30 days • Just 10 exception types generated 97,3% of all errors
  • 21. Most common errors in Java • Takipi monitoring service analysed error logs of over 1k enterprise apps • 29,965,285 exceptions over 30 days • Just 10 exception types generated 97,3% of all errors • Two most common: NullPointerException & NumberFormatException
  • 22. Most common errors in Java • Takipi monitoring service analysed error logs of over 1k enterprise apps • 29,965,285 exceptions over 30 days • Just 10 exception types generated 97,3% of all errors • Two most common: NullPointerException & NumberFormatException http://blog.takipi.com/we-crunched-1-billion-java-logged-errors-heres-what-causes-97-of-them/
  • 24. How can FP help?
  • 25. How can FP help? • Functional style makes implicit rules governing code explicit, often as a part of type signatures
  • 26. How can FP help? • Functional style makes implicit rules governing code explicit, often as a part of type signatures • Functional style avoids constructs that are not statically analysable like throwing exceptions, therefore allowing compiler to do it's job better
  • 27. How can FP help? • Functional style makes implicit rules governing code explicit, often as a part of type signatures • Functional style avoids constructs that are not statically analysable like throwing exceptions, therefore allowing compiler to do it's job better • In concurrent and parallel programming lack of mutable state removes whole classes of programming errors for free
  • 28. How can FP help? • Functional style makes implicit rules governing code explicit, often as a part of type signatures • Functional style avoids constructs that are not statically analysable like throwing exceptions, therefore allowing compiler to do it's job better • In concurrent and parallel programming lack of mutable state removes whole classes of programming errors for free • Yields an elegant and concise code :)
  • 29. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values
  • 30. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature
  • 31. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature
  • 32. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature
  • 33. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature • not feeling especially bright today? have a NullPointerException in runtime
  • 34. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature • not feeling especially bright today? have a NullPointerException in runtime
  • 35. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature • not feeling especially bright today? have a NullPointerException in runtime
  • 36. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature • not feeling especially bright today? have a NullPointerException in runtime • null is a subtype of every reference type, so it will be propagated as 
 a valid object value
  • 37. 1 package com.example; 2 3 class CharacterOps { 4 5 static Character firstCharacter(String string) { 6 return (string.length() > 0) ? string.charAt(0) : null; 7 } 8 9 static Integer getAlphabetPosition(Character character) { 10 int code = (int) character; 11 12 if (isLowerCase(code)) 13 return code - 96; 14 else if (isUpperCase(code)) 15 return code - 64; 16 else 17 return null; // or throw exception? 18 } 19 20 private static boolean isLowerCase(int code) { 21 return code >= 97 && code <= 122; 22 } 23 24 private static boolean isUpperCase(int code) { 25 return code >= 65 && code <= 90; 26 } 27 28 } Optionality
 of values • optionality of value is not explicitly known from method signature • not feeling especially bright today? have a NullPointerException in runtime • null is a subtype of every reference type, so it will be propagated as 
 a valid object value • tracking null's origination point is so much fun!
  • 38. What we want:
 composability 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 }
  • 39. What we want:
 composability 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • feeding function a "cat" is fine, we get 3 as result
  • 40. What we want:
 composability 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • feeding function a "cat" is fine, we get 3 as result java.lang.NullPointerException at com.example.CharacterOps.getAlphabetPosition(CharacterOps.java:10) at com.example.CharOpsTest.testComposability(CharOpsTest.java:14)
  • 41. What we want:
 composability 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • feeding function a "cat" is fine, we get 3 as result • doesn't work so well for 
 an empty string though java.lang.NullPointerException at com.example.CharacterOps.getAlphabetPosition(CharacterOps.java:10) at com.example.CharOpsTest.testComposability(CharOpsTest.java:14)
  • 42. 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class ActualCharOpsTest { 8 9 @Test 10 public void testNullChecks() { 11 12 Character firstChar = firstCharacter("cat"); 13 14 if (null == firstChar) { 15 // oops. what now? exception? propagate null? 16 } else { 17 // will throw NPE on digit :( 18 Integer position = getAlphabetPosition(firstChar); 19 // ... 20 } 21 22 } 23 24 } What we get:
 explicit null checks
  • 43. 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class ActualCharOpsTest { 8 9 @Test 10 public void testNullChecks() { 11 12 Character firstChar = firstCharacter("cat"); 13 14 if (null == firstChar) { 15 // oops. what now? exception? propagate null? 16 } else { 17 // will throw NPE on digit :( 18 Integer position = getAlphabetPosition(firstChar); 19 // ... 20 } 21 22 } 23 24 } • you have to remember to check for null explicitly or face NPE hunting What we get:
 explicit null checks
  • 44. 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class ActualCharOpsTest { 8 9 @Test 10 public void testNullChecks() { 11 12 Character firstChar = firstCharacter("cat"); 13 14 if (null == firstChar) { 15 // oops. what now? exception? propagate null? 16 } else { 17 // will throw NPE on digit :( 18 Integer position = getAlphabetPosition(firstChar); 19 // ... 20 } 21 22 } 23 24 } • you have to remember to check for null explicitly or face NPE hunting • methods don't compose anymore What we get:
 explicit null checks
  • 45. 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class ActualCharOpsTest { 8 9 @Test 10 public void testNullChecks() { 11 12 Character firstChar = firstCharacter("cat"); 13 14 if (null == firstChar) { 15 // oops. what now? exception? propagate null? 16 } else { 17 // will throw NPE on digit :( 18 Integer position = getAlphabetPosition(firstChar); 19 // ... 20 } 21 22 } 23 24 } • you have to remember to check for null explicitly or face NPE hunting • methods don't compose anymore • ugly :( What we get:
 explicit null checks
  • 46. 1 package com.example; 2 3 import java.util.Optional; 4 5 class SafeCharOps { 6 7 static Optional<Character> firstCharacter( 8 String string 9 ) { 10 return (string.length() > 0) ? 11 Optional.of(string.charAt(0)) : 12 Optional.empty(); 13 } 14 15 static Optional<Integer> getAlphabetPosition( 16 Character character 17 ) { 18 int code = (int) character; 19 20 return isLowerCase(code) ? Optional.of(code - 96) : 21 isUpperCase(code) ? Optional.of(code - 64) : 22 Optional.empty(); 23 } 24 25 private static boolean isLowerCase(int code) { 26 return code >= 97 && code <= 122; 27 } 28 29 private static boolean isUpperCase(int code) { 30 return code >= 65 && code <= 90; 31 } 32 33 } Introducing 
 Optional<T>
  • 47. 1 package com.example; 2 3 import java.util.Optional; 4 5 class SafeCharOps { 6 7 static Optional<Character> firstCharacter( 8 String string 9 ) { 10 return (string.length() > 0) ? 11 Optional.of(string.charAt(0)) : 12 Optional.empty(); 13 } 14 15 static Optional<Integer> getAlphabetPosition( 16 Character character 17 ) { 18 int code = (int) character; 19 20 return isLowerCase(code) ? Optional.of(code - 96) : 21 isUpperCase(code) ? Optional.of(code - 64) : 22 Optional.empty(); 23 } 24 25 private static boolean isLowerCase(int code) { 26 return code >= 97 && code <= 122; 27 } 28 29 private static boolean isUpperCase(int code) { 30 return code >= 65 && code <= 90; 31 } 32 33 } • optionality of return value is explicit in type signature Introducing 
 Optional<T>
  • 48. 1 package com.example; 2 3 import java.util.Optional; 4 5 class SafeCharOps { 6 7 static Optional<Character> firstCharacter( 8 String string 9 ) { 10 return (string.length() > 0) ? 11 Optional.of(string.charAt(0)) : 12 Optional.empty(); 13 } 14 15 static Optional<Integer> getAlphabetPosition( 16 Character character 17 ) { 18 int code = (int) character; 19 20 return isLowerCase(code) ? Optional.of(code - 96) : 21 isUpperCase(code) ? Optional.of(code - 64) : 22 Optional.empty(); 23 } 24 25 private static boolean isLowerCase(int code) { 26 return code >= 97 && code <= 122; 27 } 28 29 private static boolean isUpperCase(int code) { 30 return code >= 65 && code <= 90; 31 } 32 33 } • optionality of return value is explicit in type signature • expressions used where possible Introducing 
 Optional<T>
  • 49. Composability revisited 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 }
  • 50. Composability revisited 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • doesn't compile :(
  • 51. Composability revisited 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • doesn't compile :( • getAlphabetPosition accepts Character instances
  • 52. Composability revisited 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • doesn't compile :( • getAlphabetPosition accepts Character instances • we have Optional<Character> from
 firstCharacter call
  • 53. Composability revisited 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.CharacterOps.*; 6 7 public class CharOpsTest { 8 9 @Test 10 public void testComposability() { 11 12 getAlphabetPosition(firstCharacter("cat")); 13 14 getAlphabetPosition(firstCharacter("")); 15 16 } 17 18 } • doesn't compile :( • getAlphabetPosition accepts Character instances • we have Optional<Character> from
 firstCharacter call • how to extract value in safe manner?
  • 54. 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.Optional; 6 7 import static com.example.SafeCharOps.*; 8 9 public class OptionalCharOpsTest { 10 11 @Test 12 public void testOptionalMethods() { 13 14 Optional<Character> firstChar = 15 firstCharacter("cat"); 16 17 if (firstChar.isPresent()) { 18 19 Optional<Integer> alphabetPosition = 20 getAlphabetPosition(firstChar.get()); 21 22 if (alphabetPosition.isPresent()) { 23 Integer position = alphabetPosition.get(); 24 25 // ... 26 } 27 28 } 29 30 } 31 32 } Imperative 
 approach
  • 55. 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.Optional; 6 7 import static com.example.SafeCharOps.*; 8 9 public class OptionalCharOpsTest { 10 11 @Test 12 public void testOptionalMethods() { 13 14 Optional<Character> firstChar = 15 firstCharacter("cat"); 16 17 if (firstChar.isPresent()) { 18 19 Optional<Integer> alphabetPosition = 20 getAlphabetPosition(firstChar.get()); 21 22 if (alphabetPosition.isPresent()) { 23 Integer position = alphabetPosition.get(); 24 25 // ... 26 } 27 28 } 29 30 } 31 32 } • we've gained explicit information about optionality Imperative 
 approach
  • 56. 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.Optional; 6 7 import static com.example.SafeCharOps.*; 8 9 public class OptionalCharOpsTest { 10 11 @Test 12 public void testOptionalMethods() { 13 14 Optional<Character> firstChar = 15 firstCharacter("cat"); 16 17 if (firstChar.isPresent()) { 18 19 Optional<Integer> alphabetPosition = 20 getAlphabetPosition(firstChar.get()); 21 22 if (alphabetPosition.isPresent()) { 23 Integer position = alphabetPosition.get(); 24 25 // ... 26 } 27 28 } 29 30 } 31 32 } • we've gained explicit information about optionality • still looks like null checks :( Imperative 
 approach
  • 57. 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.Optional; 6 7 import static com.example.SafeCharOps.*; 8 9 public class OptionalCharOpsTest { 10 11 @Test 12 public void testOptionalMethods() { 13 14 Optional<Character> firstChar = 15 firstCharacter("cat"); 16 17 if (firstChar.isPresent()) { 18 19 Optional<Integer> alphabetPosition = 20 getAlphabetPosition(firstChar.get()); 21 22 if (alphabetPosition.isPresent()) { 23 Integer position = alphabetPosition.get(); 24 25 // ... 26 } 27 28 } 29 30 } 31 32 } • we've gained explicit information about optionality • still looks like null checks :( • still breaks composability :( Imperative 
 approach
  • 58. Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 59. • no null checks! Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 60. • no null checks! • clean functional composition Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 61. • no null checks! • clean functional composition • type safety, IDE helps at every step as type inference is easy Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 62. • no null checks! • clean functional composition • type safety, IDE helps at every step as type inference is easy • easier to refactor Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 63. • no null checks! • clean functional composition • type safety, IDE helps at every step as type inference is easy • easier to refactor • elegant & succinct Functional 
 approach 1 package com.example; 2 3 import org.junit.Test; 4 5 import static com.example.SafeCharOps.*; 6 7 public class OptionalCharOpsTest { 8 9 @Test 10 public void testOptionalMethods() { 11 12 firstCharacter("cat") 13 .flatMap(SafeCharOps::getAlphabetPosition) 14 .ifPresent(value -> { 15 assert value == 3; 16 }); 17 18 assert !firstCharacter("") 19 .flatMap(SafeCharOps::getAlphabetPosition) 20 .isPresent(); 21 } 22 23 }
  • 64. 1 package com.example; 2 3 import java.util.List; 4 import java.util.stream.Collectors; 5 6 class StreamsAndErrors { 7 8 static List<Integer> toNumbers(List<String> strings) { 9 return strings.stream() 10 .map(Integer::parseInt) 11 .collect(Collectors.toList()); 12 } 13 14 } Streams API
 revisited: errors 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("1", "2", "3"); 15 out.println(StreamsAndErrors.toNumbers(strings)); 16 // prints '[1, 2, 3]' 17 18 List<String> itsaTrap = asList("1", "a", "3"); 19 out.println(StreamsAndErrors.toNumbers(itsaTrap)); 20 // NumberFormatException: For input string: "a" 21 } 22 23 }
  • 65. 1 package com.example; 2 3 import java.util.List; 4 import java.util.stream.Collectors; 5 6 class StreamsAndErrors { 7 8 static List<Integer> toNumbers(List<String> strings) { 9 return strings.stream() 10 .map(Integer::parseInt) 11 .collect(Collectors.toList()); 12 } 13 14 } • generic string to integer conversion on collection level Streams API
 revisited: errors 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("1", "2", "3"); 15 out.println(StreamsAndErrors.toNumbers(strings)); 16 // prints '[1, 2, 3]' 17 18 List<String> itsaTrap = asList("1", "a", "3"); 19 out.println(StreamsAndErrors.toNumbers(itsaTrap)); 20 // NumberFormatException: For input string: "a" 21 } 22 23 }
  • 66. 1 package com.example; 2 3 import java.util.List; 4 import java.util.stream.Collectors; 5 6 class StreamsAndErrors { 7 8 static List<Integer> toNumbers(List<String> strings) { 9 return strings.stream() 10 .map(Integer::parseInt) 11 .collect(Collectors.toList()); 12 } 13 14 } • generic string to integer conversion on collection level • type signature tells nothing about possible of failure Streams API
 revisited: errors 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("1", "2", "3"); 15 out.println(StreamsAndErrors.toNumbers(strings)); 16 // prints '[1, 2, 3]' 17 18 List<String> itsaTrap = asList("1", "a", "3"); 19 out.println(StreamsAndErrors.toNumbers(itsaTrap)); 20 // NumberFormatException: For input string: "a" 21 } 22 23 }
  • 67. 1 package com.example; 2 3 import java.util.List; 4 import java.util.stream.Collectors; 5 6 class StreamsAndErrors { 7 8 static List<Integer> toNumbers(List<String> strings) { 9 return strings.stream() 10 .map(Integer::parseInt) 11 .collect(Collectors.toList()); 12 } 13 14 } • generic string to integer conversion on collection level • type signature tells nothing about possible of failure • programmer knows (let's hope so) about possibility of failure and has to deal with it explicitly Streams API
 revisited: errors 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("1", "2", "3"); 15 out.println(StreamsAndErrors.toNumbers(strings)); 16 // prints '[1, 2, 3]' 17 18 List<String> itsaTrap = asList("1", "a", "3"); 19 out.println(StreamsAndErrors.toNumbers(itsaTrap)); 20 // NumberFormatException: For input string: "a" 21 } 22 23 }
  • 68. 1 package com.example; 2 3 import java.util.List; 4 import java.util.Objects; 5 import java.util.Optional; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Integer> filterOut(List<String> strings) { 11 return strings.stream() 12 .map(s -> { 13 try { 14 return Integer.parseInt(s); 15 } catch (NumberFormatException nfe) { 16 return null; 17 } 18 }) 19 .filter(Objects::nonNull) 20 .collect(Collectors.toList()); 21 } 22 23 static Optional<List<Integer>> failOnFirst( 24 List<String> strings 25 ) { 26 try { 27 return Optional.of( 28 strings.stream() 29 .map(Integer::parseInt) 30 .collect(Collectors.toList()) 31 ); 32 } catch (NumberFormatException nfe) { 33 return Optional.empty(); 34 } 35 } 36 37 } Handling errors 
 with try
  • 69. 1 package com.example; 2 3 import java.util.List; 4 import java.util.Objects; 5 import java.util.Optional; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Integer> filterOut(List<String> strings) { 11 return strings.stream() 12 .map(s -> { 13 try { 14 return Integer.parseInt(s); 15 } catch (NumberFormatException nfe) { 16 return null; 17 } 18 }) 19 .filter(Objects::nonNull) 20 .collect(Collectors.toList()); 21 } 22 23 static Optional<List<Integer>> failOnFirst( 24 List<String> strings 25 ) { 26 try { 27 return Optional.of( 28 strings.stream() 29 .map(Integer::parseInt) 30 .collect(Collectors.toList()) 31 ); 32 } catch (NumberFormatException nfe) { 33 return Optional.empty(); 34 } 35 } 36 37 } • ughh... null again :( Handling errors 
 with try
  • 70. 1 package com.example; 2 3 import java.util.List; 4 import java.util.Objects; 5 import java.util.Optional; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Integer> filterOut(List<String> strings) { 11 return strings.stream() 12 .map(s -> { 13 try { 14 return Integer.parseInt(s); 15 } catch (NumberFormatException nfe) { 16 return null; 17 } 18 }) 19 .filter(Objects::nonNull) 20 .collect(Collectors.toList()); 21 } 22 23 static Optional<List<Integer>> failOnFirst( 24 List<String> strings 25 ) { 26 try { 27 return Optional.of( 28 strings.stream() 29 .map(Integer::parseInt) 30 .collect(Collectors.toList()) 31 ); 32 } catch (NumberFormatException nfe) { 33 return Optional.empty(); 34 } 35 } 36 37 } • ughh... null again :( • we have to filter nulls out lest we create a disaster waiting to happen Handling errors 
 with try
  • 71. 1 package com.example; 2 3 import java.util.List; 4 import java.util.Objects; 5 import java.util.Optional; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Integer> filterOut(List<String> strings) { 11 return strings.stream() 12 .map(s -> { 13 try { 14 return Integer.parseInt(s); 15 } catch (NumberFormatException nfe) { 16 return null; 17 } 18 }) 19 .filter(Objects::nonNull) 20 .collect(Collectors.toList()); 21 } 22 23 static Optional<List<Integer>> failOnFirst( 24 List<String> strings 25 ) { 26 try { 27 return Optional.of( 28 strings.stream() 29 .map(Integer::parseInt) 30 .collect(Collectors.toList()) 31 ); 32 } catch (NumberFormatException nfe) { 33 return Optional.empty(); 34 } 35 } 36 37 } • ughh... null again :( • we have to filter nulls out lest we create a disaster waiting to happen • using Optional tells caller that this method might yield value, but doesn't say anything about errors that may happen inside Handling errors 
 with try
  • 72. Handling errors 
 with Try 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Try<Integer>> withErrs(List<String> strings) { 11 return strings.stream() 12 .map(s -> Try.of(() -> Integer.parseInt(s))) 13 .collect(Collectors.toList()); 14 } 15 16 static Try<List<Integer>> failOnFirst( 17 List<String> strings 18 ) { 19 return Try.of(() -> strings.stream() 20 .map(Integer::parseInt) 21 .collect(Collectors.toList())); 22 } 23 24 }
  • 73. • type signature explicitly informs us about the possibility of error Handling errors 
 with Try 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Try<Integer>> withErrs(List<String> strings) { 11 return strings.stream() 12 .map(s -> Try.of(() -> Integer.parseInt(s))) 13 .collect(Collectors.toList()); 14 } 15 16 static Try<List<Integer>> failOnFirst( 17 List<String> strings 18 ) { 19 return Try.of(() -> strings.stream() 20 .map(Integer::parseInt) 21 .collect(Collectors.toList())); 22 } 23 24 }
  • 74. • type signature explicitly informs us about the possibility of error • exceptions are caught inside stream or in lambda wrapping whole stream processing Handling errors 
 with Try 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndErrors { 9 10 static List<Try<Integer>> withErrs(List<String> strings) { 11 return strings.stream() 12 .map(s -> Try.of(() -> Integer.parseInt(s))) 13 .collect(Collectors.toList()); 14 } 15 16 static Try<List<Integer>> failOnFirst( 17 List<String> strings 18 ) { 19 return Try.of(() -> strings.stream() 20 .map(Integer::parseInt) 21 .collect(Collectors.toList())); 22 } 23 24 }
  • 75. 1 package com.example; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndCheckedExceptions { 9 10 private static SimpleDateFormat sdf = 11 new SimpleDateFormat("ddMMyyyy"); 12 13 static List<Date> parseAll(List<String> strings) { 14 return strings.stream() 15 .map(sdf::parse) // won't compile! 16 .collect(Collectors.toList()); 17 } 18 19 } Checked exceptions 
 & Java 8 Streams:
 Rough edges
  • 76. 1 package com.example; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndCheckedExceptions { 9 10 private static SimpleDateFormat sdf = 11 new SimpleDateFormat("ddMMyyyy"); 12 13 static List<Date> parseAll(List<String> strings) { 14 return strings.stream() 15 .map(sdf::parse) // won't compile! 16 .collect(Collectors.toList()); 17 } 18 19 } • ParseException is checked, which breaks lambda expression Checked exceptions 
 & Java 8 Streams:
 Rough edges
  • 77. 1 package com.example; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndCheckedExceptions { 9 10 private static SimpleDateFormat sdf = 11 new SimpleDateFormat("ddMMyyyy"); 12 13 static List<Date> parseAll(List<String> strings) { 14 return strings.stream() 15 .map(sdf::parse) // won't compile! 16 .collect(Collectors.toList()); 17 } 18 19 } • ParseException is checked, which breaks lambda expression Checked exceptions 
 & Java 8 Streams:
 Rough edges
  • 78. 1 package com.example; 2 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.List; 6 import java.util.stream.Collectors; 7 8 class StreamsAndCheckedExceptions { 9 10 private static SimpleDateFormat sdf = 11 new SimpleDateFormat("ddMMyyyy"); 12 13 static List<Date> parseAll(List<String> strings) { 14 return strings.stream() 15 .map(sdf::parse) // won't compile! 16 .collect(Collectors.toList()); 17 } 18 19 } • ParseException is checked, which breaks lambda expression • solution using try-catch & rethrow-as-unchecked block is ugly and defeats the purpose of lambdas Checked exceptions 
 & Java 8 Streams:
 Rough edges
  • 79. Checked exceptions 
 & Java 8 Streams:
 Try to the rescue 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.List; 8 import java.util.stream.Collectors; 9 10 class StreamsAndCheckedExceptions { 11 12 private static SimpleDateFormat sdf = 13 new SimpleDateFormat("ddMMyyyy"); 14 15 static List<Try<Date>> parseAll(List<String> strings) { 16 return strings.stream() 17 .map(s -> Try.of(() -> sdf.parse(s))) 18 .collect(Collectors.toList()); 19 } 20 21 } 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("10042017", "23"); 15 out.println( 16 StreamsAndCheckedExceptions.parseAll(strings) 17 ); 18 19 // [ 20 // Success(Mon Apr 10 00:00:00 CEST 2017), 21 // Failure(ParseException: Unparseable date: "23") 22 // ] 23 } 24 25 }
  • 80. • problem of checked exceptions solved
 Checked exceptions 
 & Java 8 Streams:
 Try to the rescue 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.List; 8 import java.util.stream.Collectors; 9 10 class StreamsAndCheckedExceptions { 11 12 private static SimpleDateFormat sdf = 13 new SimpleDateFormat("ddMMyyyy"); 14 15 static List<Try<Date>> parseAll(List<String> strings) { 16 return strings.stream() 17 .map(s -> Try.of(() -> sdf.parse(s))) 18 .collect(Collectors.toList()); 19 } 20 21 } 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("10042017", "23"); 15 out.println( 16 StreamsAndCheckedExceptions.parseAll(strings) 17 ); 18 19 // [ 20 // Success(Mon Apr 10 00:00:00 CEST 2017), 21 // Failure(ParseException: Unparseable date: "23") 22 // ] 23 } 24 25 }
  • 81. • problem of checked exceptions solved
 • we also gained explicit information of possibility of failure Checked exceptions 
 & Java 8 Streams:
 Try to the rescue 1 package com.example; 2 3 import javaslang.control.Try; 4 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7 import java.util.List; 8 import java.util.stream.Collectors; 9 10 class StreamsAndCheckedExceptions { 11 12 private static SimpleDateFormat sdf = 13 new SimpleDateFormat("ddMMyyyy"); 14 15 static List<Try<Date>> parseAll(List<String> strings) { 16 return strings.stream() 17 .map(s -> Try.of(() -> sdf.parse(s))) 18 .collect(Collectors.toList()); 19 } 20 21 } 1 package com.example; 2 3 import org.junit.Test; 4 5 import java.util.List; 6 7 import static java.lang.System.out; 8 import static java.util.Arrays.asList; 9 10 public class StreamsTest { 11 12 @Test 13 public void testNumberConversion() { 14 List<String> strings = asList("10042017", "23"); 15 out.println( 16 StreamsAndCheckedExceptions.parseAll(strings) 17 ); 18 19 // [ 20 // Success(Mon Apr 10 00:00:00 CEST 2017), 21 // Failure(ParseException: Unparseable date: "23") 22 // ] 23 } 24 25 }
  • 83. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state
  • 84. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state • Shared mutable state in concurrent environment requires synchronisation which is difficult and leads to subtle and 
 hard to replicate bugs
  • 85. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state • Shared mutable state in concurrent environment requires synchronisation which is difficult and leads to subtle and 
 hard to replicate bugs • Immutable objects and persistent data structures have none of those problems
  • 86. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state • Shared mutable state in concurrent environment requires synchronisation which is difficult and leads to subtle and 
 hard to replicate bugs • Immutable objects and persistent data structures have none of those problems • it's trivial to protect invariants once instance is immutable
  • 87. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state • Shared mutable state in concurrent environment requires synchronisation which is difficult and leads to subtle and 
 hard to replicate bugs • Immutable objects and persistent data structures have none of those problems • it's trivial to protect invariants once instance is immutable • no need for synchronisation ever
  • 88. Case for immutable data • Mutable state makes it significantly harder to reason about a system due to multiple code branches that can lead to mutation of state • Shared mutable state in concurrent environment requires synchronisation which is difficult and leads to subtle and 
 hard to replicate bugs • Immutable objects and persistent data structures have none of those problems • it's trivial to protect invariants once instance is immutable • no need for synchronisation ever ... so how to do this in Java?
  • 89. Immutable objects
 in plain Java 1 package com.example; 2 3 import java.util.Set; 4 5 public class Office { 6 7 private final Set<Room> rooms; 8 private final Set<Employee> employees; 9 10 public Office(Set<Room> rooms, Set<Employee> employees) { 11 this.rooms = rooms; 12 this.employees = employees; 13 } 14 15 public Set<Room> getRooms() { 16 return rooms; 17 } 18 19 public Set<Employee> getEmployees() { 20 return employees; 21 } 22 23 }
  • 90. Immutable objects
 in plain Java • lots of getter noise1 package com.example; 2 3 import java.util.Set; 4 5 public class Office { 6 7 private final Set<Room> rooms; 8 private final Set<Employee> employees; 9 10 public Office(Set<Room> rooms, Set<Employee> employees) { 11 this.rooms = rooms; 12 this.employees = employees; 13 } 14 15 public Set<Room> getRooms() { 16 return rooms; 17 } 18 19 public Set<Employee> getEmployees() { 20 return employees; 21 } 22 23 }
  • 91. Immutable objects
 in plain Java • lots of getter noise • if we want a builder, we have to create one and make constructor private 1 package com.example; 2 3 import java.util.Set; 4 5 public class Office { 6 7 private final Set<Room> rooms; 8 private final Set<Employee> employees; 9 10 public Office(Set<Room> rooms, Set<Employee> employees) { 11 this.rooms = rooms; 12 this.employees = employees; 13 } 14 15 public Set<Room> getRooms() { 16 return rooms; 17 } 18 19 public Set<Employee> getEmployees() { 20 return employees; 21 } 22 23 }
  • 92. Immutable objects
 in plain Java • lots of getter noise • if we want a builder, we have to create one and make constructor private • optional field is painful as IDE will cry that fields should never have type Optional<T> 1 package com.example; 2 3 import java.util.Set; 4 5 public class Office { 6 7 private final Set<Room> rooms; 8 private final Set<Employee> employees; 9 10 public Office(Set<Room> rooms, Set<Employee> employees) { 11 this.rooms = rooms; 12 this.employees = employees; 13 } 14 15 public Set<Room> getRooms() { 16 return rooms; 17 } 18 19 public Set<Employee> getEmployees() { 20 return employees; 21 } 22 23 }
  • 93. Immutable objects
 in plain Java • lots of getter noise • if we want a builder, we have to create one and make constructor private • optional field is painful as IDE will cry that fields should never have type Optional<T> • how can we get a copy of instance with only one field modified? 1 package com.example; 2 3 import java.util.Set; 4 5 public class Office { 6 7 private final Set<Room> rooms; 8 private final Set<Employee> employees; 9 10 public Office(Set<Room> rooms, Set<Employee> employees) { 11 this.rooms = rooms; 12 this.employees = employees; 13 } 14 15 public Set<Room> getRooms() { 16 return rooms; 17 } 18 19 public Set<Employee> getEmployees() { 20 return employees; 21 } 22 23 }
  • 94. Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 95. • that's all! Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 96. • that's all! • highly customisable code generation Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 97. • that's all! • highly customisable code generation • handles Optional<T> values correctly Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 98. • that's all! • highly customisable code generation • handles Optional<T> values correctly • handles default values Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 99. • that's all! • highly customisable code generation • handles Optional<T> values correctly • handles default values • Jackson / Gson integration out- of-the-box Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 100. • that's all! • highly customisable code generation • handles Optional<T> values correctly • handles default values • Jackson / Gson integration out- of-the-box • provides with* methods allowing painless modification of immutable instances Enter Immutables 1 package com.example; 2 3 import javaslang.collection.Set; 4 import org.immutables.value.Value; 5 6 @Value.Immutable 7 @Value.Style(typeImmutable = "*") 8 abstract class AbstractOffice { 9 abstract Set<Room> rooms(); 10 11 abstract Set<Employee> employees(); 12 13 abstract boolean open(); 14 }
  • 101. Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 102. • named factory method can be generated (of by default) Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 103. • named factory method can be generated (of by default) • builder class is generated by default Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 104. • named factory method can be generated (of by default) • builder class is generated by default • toString, hashCode and equals are generated using best practice methods Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 105. • named factory method can be generated (of by default) • builder class is generated by default • toString, hashCode and equals are generated using best practice methods • with(field) methods make obtaining modified instances a breeze! Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 106. • named factory method can be generated (of by default) • builder class is generated by default • toString, hashCode and equals are generated using best practice methods • with(field) methods make obtaining modified instances a breeze! • nulls are not allowed by default, so fail early rule is enforced Immutables in action 1 package com.example; 2 3 import javaslang.collection.HashSet; 4 import org.junit.Test; 5 6 public class OfficeTest { 7 8 @Test 9 public void muchSafeSuchImmutableVeryWow() { 10 11 HashSet<Employee> employees = HashSet.of( 12 Employee.of("Boss") 13 ); 14 15 HashSet<Room> rooms = HashSet.of( 16 Room.of("Boss' office") 17 ); 18 19 Office office = Office.builder() 20 .employees(employees) 21 .rooms(rooms) 22 .open(true) 23 .build(); 24 25 System.out.println(office); 26 // Office{ 27 // rooms=HashSet(Room{name=Boss' office}), 28 // employees=HashSet(Employee{name=Boss}), 29 // open=true} 30 31 Office officeWithoutEmployees = office 32 .withEmployees(HashSet.empty()) 33 .withOpen(false); 34 35 System.out.println(officeWithoutEmployees); 36 // Office{ 37 // rooms=HashSet(Room{name=Boss' office}), 38 // employees=HashSet(), 39 // open=false} 40 } 41 }
  • 108. About that 
 javaslang.collection.HashSet • Javaslang provides immutable, persistent, purely functional collections that match Java Collections
  • 109. About that 
 javaslang.collection.HashSet • Javaslang provides immutable, persistent, purely functional collections that match Java Collections • Immutable, so every operation returns a new instance
  • 110. About that 
 javaslang.collection.HashSet • Javaslang provides immutable, persistent, purely functional collections that match Java Collections • Immutable, so every operation returns a new instance • Persistent, so creation of new instance means that data is shared between instances of collection and only the reference to modified element is replaced
  • 111. About that 
 javaslang.collection.HashSet • Javaslang provides immutable, persistent, purely functional collections that match Java Collections • Immutable, so every operation returns a new instance • Persistent, so creation of new instance means that data is shared between instances of collection and only the reference to modified element is replaced • Functional, so all operations are referentially transparent
 (at least as long as values stored in collection are immutable!)
  • 113. • classic, imperative approach with StringBuilder: for loop and append calls Javaslang 
 Collections APIs
  • 114. 1 String join(String... words) { 2 StringBuilder builder = new StringBuilder(); 3 for(String s : words) { 4 if (builder.length() > 0) { 5 builder.append(", "); 6 } 7 builder.append(s); 8 } 9 return builder.toString(); 10 } • classic, imperative approach with StringBuilder: for loop and append calls Javaslang 
 Collections APIs
  • 115. 1 String join(String... words) { 2 StringBuilder builder = new StringBuilder(); 3 for(String s : words) { 4 if (builder.length() > 0) { 5 builder.append(", "); 6 } 7 builder.append(s); 8 } 9 return builder.toString(); 10 } • classic, imperative approach with StringBuilder: for loop and append calls • declarative use of List methods and fold (reduce to accumulator value) Javaslang 
 Collections APIs
  • 116. 1 String join(String... words) { 2 StringBuilder builder = new StringBuilder(); 3 for(String s : words) { 4 if (builder.length() > 0) { 5 builder.append(", "); 6 } 7 builder.append(s); 8 } 9 return builder.toString(); 10 } 1 String join(String... words) { 2 return List.of(words) 3 .intersperse(", ") 4 .fold("", String::concat); 5 } • classic, imperative approach with StringBuilder: for loop and append calls • declarative use of List methods and fold (reduce to accumulator value) Javaslang 
 Collections APIs
  • 117. 1 String join(String... words) { 2 StringBuilder builder = new StringBuilder(); 3 for(String s : words) { 4 if (builder.length() > 0) { 5 builder.append(", "); 6 } 7 builder.append(s); 8 } 9 return builder.toString(); 10 } 1 String join(String... words) { 2 return List.of(words) 3 .intersperse(", ") 4 .fold("", String::concat); 5 } • classic, imperative approach with StringBuilder: for loop and append calls • declarative use of List methods and fold (reduce to accumulator value) • a helper method! Javaslang 
 Collections APIs
  • 118. 1 String join(String... words) { 2 StringBuilder builder = new StringBuilder(); 3 for(String s : words) { 4 if (builder.length() > 0) { 5 builder.append(", "); 6 } 7 builder.append(s); 8 } 9 return builder.toString(); 10 } 1 String join(String... words) { 2 return List.of(words) 3 .intersperse(", ") 4 .fold("", String::concat); 5 } 1 List.of(words).mkString(", "); • classic, imperative approach with StringBuilder: for loop and append calls • declarative use of List methods and fold (reduce to accumulator value) • a helper method! Javaslang 
 Collections APIs
  • 119. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.HashSet; 6 import javaslang.collection.Map; 7 import javaslang.collection.Set; 8 9 public class PhoneNumberData { 10 11 public static final Set<String> phoneNumbers = 12 HashSet.of( 13 "+48413422345", 14 "413572456", 15 "+48413456990", 16 "48225697246", 17 "+48224914634", 18 "48126434972", 19 "+48128275242" 20 ); 21 22 public static final Map<String, String> areas = 23 HashMap.ofEntries( 24 Tuple.of("41", "Kielce"), 25 Tuple.of("22", "Warszawa"), 26 Tuple.of("12", "Kraków") 27 ); 28 29 } A more complex 
 example...
  • 120. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.HashSet; 6 import javaslang.collection.Map; 7 import javaslang.collection.Set; 8 9 public class PhoneNumberData { 10 11 public static final Set<String> phoneNumbers = 12 HashSet.of( 13 "+48413422345", 14 "413572456", 15 "+48413456990", 16 "48225697246", 17 "+48224914634", 18 "48126434972", 19 "+48128275242" 20 ); 21 22 public static final Map<String, String> areas = 23 HashMap.ofEntries( 24 Tuple.of("41", "Kielce"), 25 Tuple.of("22", "Warszawa"), 26 Tuple.of("12", "Kraków") 27 ); 28 29 } • phoneNumbers: phone numbers in different formats A more complex 
 example...
  • 121. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.HashSet; 6 import javaslang.collection.Map; 7 import javaslang.collection.Set; 8 9 public class PhoneNumberData { 10 11 public static final Set<String> phoneNumbers = 12 HashSet.of( 13 "+48413422345", 14 "413572456", 15 "+48413456990", 16 "48225697246", 17 "+48224914634", 18 "48126434972", 19 "+48128275242" 20 ); 21 22 public static final Map<String, String> areas = 23 HashMap.ofEntries( 24 Tuple.of("41", "Kielce"), 25 Tuple.of("22", "Warszawa"), 26 Tuple.of("12", "Kraków") 27 ); 28 29 } • phoneNumbers: phone numbers in different formats • areas: maps prefixes to area names A more complex 
 example...
  • 122. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.HashSet; 6 import javaslang.collection.Map; 7 import javaslang.collection.Set; 8 9 public class PhoneNumberData { 10 11 public static final Set<String> phoneNumbers = 12 HashSet.of( 13 "+48413422345", 14 "413572456", 15 "+48413456990", 16 "48225697246", 17 "+48224914634", 18 "48126434972", 19 "+48128275242" 20 ); 21 22 public static final Map<String, String> areas = 23 HashMap.ofEntries( 24 Tuple.of("41", "Kielce"), 25 Tuple.of("22", "Warszawa"), 26 Tuple.of("12", "Kraków") 27 ); 28 29 } • phoneNumbers: phone numbers in different formats • areas: maps prefixes to area names • task: group numbers by area name A more complex 
 example...
  • 123. Processing!1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 124. Processing!1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 125. Processing! • filter out numbers that are too short 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 126. Processing! • filter out numbers that are too short 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 127. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 128. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 129. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! • strip international code from processed tuple entry, don't do anything to original 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 130. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! • strip international code from processed tuple entry, don't do anything to original 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 131. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! • strip international code from processed tuple entry, don't do anything to original • group tuples by area code obtained from processed tuple entry 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 132. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! • strip international code from processed tuple entry, don't do anything to original • group tuples by area code obtained from processed tuple entry 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 133. Processing! • filter out numbers that are too short • we need to have original number and still process it - Tuples! • strip international code from processed tuple entry, don't do anything to original • group tuples by area code obtained from processed tuple entry • map keys and values to either area name and set of original phone numbers 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import javaslang.collection.HashMap; 6 import javaslang.collection.HashSet; 7 import javaslang.collection.Map; 8 import javaslang.collection.Set; 9 import org.junit.Test; 10 11 import static java.util.function.Function.identity; 12 import static com.example.PhoneNumberData.*; 13 14 public class GroupNumbersTest { 15 16 @Test 17 public void processNumbers() { 18 Map<String, Set<String>> map = phoneNumbers 19 .filter(num -> num.length() >= 9) 20 .map(number -> Tuple.of(number, number)) 21 .map(tuple -> 22 tuple.map( 23 num -> num.replaceFirst("^+?48", ""), 24 identity() 25 ) 26 ) 27 .groupBy(tuple -> tuple._1().substring(0, 2)) 28 .bimap( 29 key -> areas.get(key).getOrElse("Nieznany"), 30 value -> value.map(Tuple2::_2) 31 ); 32 33 System.out.println(map); 34 } 35 36 }
  • 135. Results: HashMap(
 (Kielce, HashSet(+48413456990, +48413422345, 413572456)), 
 (Kraków, HashSet(+48128275242, 48126434972)), 
 (Warszawa, HashSet(+48224914634, 48225697246))
 )
  • 136. Results: HashMap(
 (Kielce, HashSet(+48413456990, +48413422345, 413572456)), 
 (Kraków, HashSet(+48128275242, 48126434972)), 
 (Warszawa, HashSet(+48224914634, 48225697246))
 ) ... neat!

  • 137. Results: HashMap(
 (Kielce, HashSet(+48413456990, +48413422345, 413572456)), 
 (Kraków, HashSet(+48128275242, 48126434972)), 
 (Warszawa, HashSet(+48224914634, 48225697246))
 ) ... neat!
 But what if that was an infinite stream of phone numbers?
  • 138. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.Map; 6 import rx.Observable; 7 8 public class StreamingPhoneNumberData { 9 10 public static final Observable<String> phoneNumbers = 11 Observable.from(new String[]{ 12 "+48413422345", 13 "413572456", 14 "+48413456990", 15 "48225697246", 16 "+48224914634", 17 "48126434972", 18 "+48128275242" 19 }); 20 21 public static final Map<String, String> areas = 22 HashMap.ofEntries( 23 Tuple.of("41", "Kielce"), 24 Tuple.of("22", "Warszawa"), 25 Tuple.of("12", "Kraków") 26 ); 27 28 } Event streams 
 with RxJava
  • 139. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.Map; 6 import rx.Observable; 7 8 public class StreamingPhoneNumberData { 9 10 public static final Observable<String> phoneNumbers = 11 Observable.from(new String[]{ 12 "+48413422345", 13 "413572456", 14 "+48413456990", 15 "48225697246", 16 "+48224914634", 17 "48126434972", 18 "+48128275242" 19 }); 20 21 public static final Map<String, String> areas = 22 HashMap.ofEntries( 23 Tuple.of("41", "Kielce"), 24 Tuple.of("22", "Warszawa"), 25 Tuple.of("12", "Kraków") 26 ); 27 28 } Event streams 
 with RxJava
  • 140. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.collection.HashMap; 5 import javaslang.collection.Map; 6 import rx.Observable; 7 8 public class StreamingPhoneNumberData { 9 10 public static final Observable<String> phoneNumbers = 11 Observable.from(new String[]{ 12 "+48413422345", 13 "413572456", 14 "+48413456990", 15 "48225697246", 16 "+48224914634", 17 "48126434972", 18 "+48128275242" 19 }); 20 21 public static final Map<String, String> areas = 22 HashMap.ofEntries( 23 Tuple.of("41", "Kielce"), 24 Tuple.of("22", "Warszawa"), 25 Tuple.of("12", "Kraków") 26 ); 27 28 } Event streams 
 with RxJava • Observable<T> is 
 a 0 .. n collection of events (potentially infinite!)
  • 141. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import org.junit.Test; 6 import rx.observables.GroupedObservable; 7 8 import static com.example.PhoneNumberData.areas; 9 import static com.example.StreamingData.phoneNumbers; 10 import static java.lang.System.out; 11 import static java.util.function.Function.identity; 12 13 public class RxGroupPhoneNumbersTest { 14 15 @Test 16 public void processNumbers() { 17 phoneNumbers 18 .filter(num -> num.length() >= 9) 19 .map(number -> Tuple.of(number, number)) 20 .map(tuple -> 21 tuple.map( 22 num -> num.replaceFirst("^+?48", ""), 23 identity() 24 ) 25 ) 26 .groupBy(tuple -> tuple._1().substring(0, 2)) 27 .map(grouped -> 28 GroupedObservable.from( 29 areas.get(grouped.getKey()) 30 .getOrElse("Unknown"), 31 grouped.map(Tuple2::_2) 32 ) 33 ) 34 .forEach(grouped -> grouped.forEach(number -> 35 out.println( 36 grouped.getKey() + ": " + number 37 ) 38 ) 39 ); 40 } 41 42 } Event streams 
 with RxJava: 
 reuse your lambdas!
  • 142. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import org.junit.Test; 6 import rx.observables.GroupedObservable; 7 8 import static com.example.PhoneNumberData.areas; 9 import static com.example.StreamingData.phoneNumbers; 10 import static java.lang.System.out; 11 import static java.util.function.Function.identity; 12 13 public class RxGroupPhoneNumbersTest { 14 15 @Test 16 public void processNumbers() { 17 phoneNumbers 18 .filter(num -> num.length() >= 9) 19 .map(number -> Tuple.of(number, number)) 20 .map(tuple -> 21 tuple.map( 22 num -> num.replaceFirst("^+?48", ""), 23 identity() 24 ) 25 ) 26 .groupBy(tuple -> tuple._1().substring(0, 2)) 27 .map(grouped -> 28 GroupedObservable.from( 29 areas.get(grouped.getKey()) 30 .getOrElse("Unknown"), 31 grouped.map(Tuple2::_2) 32 ) 33 ) 34 .forEach(grouped -> grouped.forEach(number -> 35 out.println( 36 grouped.getKey() + ": " + number 37 ) 38 ) 39 ); 40 } 41 42 } Event streams 
 with RxJava: 
 reuse your lambdas!
  • 143. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import org.junit.Test; 6 import rx.observables.GroupedObservable; 7 8 import static com.example.PhoneNumberData.areas; 9 import static com.example.StreamingData.phoneNumbers; 10 import static java.lang.System.out; 11 import static java.util.function.Function.identity; 12 13 public class RxGroupPhoneNumbersTest { 14 15 @Test 16 public void processNumbers() { 17 phoneNumbers 18 .filter(num -> num.length() >= 9) 19 .map(number -> Tuple.of(number, number)) 20 .map(tuple -> 21 tuple.map( 22 num -> num.replaceFirst("^+?48", ""), 23 identity() 24 ) 25 ) 26 .groupBy(tuple -> tuple._1().substring(0, 2)) 27 .map(grouped -> 28 GroupedObservable.from( 29 areas.get(grouped.getKey()) 30 .getOrElse("Unknown"), 31 grouped.map(Tuple2::_2) 32 ) 33 ) 34 .forEach(grouped -> grouped.forEach(number -> 35 out.println( 36 grouped.getKey() + ": " + number 37 ) 38 ) 39 ); 40 } 41 42 } Event streams 
 with RxJava: 
 reuse your lambdas! • highlighted code is the same as code used on Javaslang collection!
  • 144. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import org.junit.Test; 6 import rx.observables.GroupedObservable; 7 8 import static com.example.PhoneNumberData.areas; 9 import static com.example.StreamingData.phoneNumbers; 10 import static java.lang.System.out; 11 import static java.util.function.Function.identity; 12 13 public class RxGroupPhoneNumbersTest { 14 15 @Test 16 public void processNumbers() { 17 phoneNumbers 18 .filter(num -> num.length() >= 9) 19 .map(number -> Tuple.of(number, number)) 20 .map(tuple -> 21 tuple.map( 22 num -> num.replaceFirst("^+?48", ""), 23 identity() 24 ) 25 ) 26 .groupBy(tuple -> tuple._1().substring(0, 2)) 27 .map(grouped -> 28 GroupedObservable.from( 29 areas.get(grouped.getKey()) 30 .getOrElse("Unknown"), 31 grouped.map(Tuple2::_2) 32 ) 33 ) 34 .forEach(grouped -> grouped.forEach(number -> 35 out.println( 36 grouped.getKey() + ": " + number 37 ) 38 ) 39 ); 40 } 41 42 } Event streams 
 with RxJava: 
 reuse your lambdas! • highlighted code is the same as code used on Javaslang collection! • we are operating on potentially infinite stream, so groupBy returns Observable of GroupedObservables - a stream of streams of values grouped by key!
  • 145. 1 package com.example; 2 3 import javaslang.Tuple; 4 import javaslang.Tuple2; 5 import org.junit.Test; 6 import rx.observables.GroupedObservable; 7 8 import static com.example.PhoneNumberData.areas; 9 import static com.example.StreamingData.phoneNumbers; 10 import static java.lang.System.out; 11 import static java.util.function.Function.identity; 12 13 public class RxGroupPhoneNumbersTest { 14 15 @Test 16 public void processNumbers() { 17 phoneNumbers 18 .filter(num -> num.length() >= 9) 19 .map(number -> Tuple.of(number, number)) 20 .map(tuple -> 21 tuple.map( 22 num -> num.replaceFirst("^+?48", ""), 23 identity() 24 ) 25 ) 26 .groupBy(tuple -> tuple._1().substring(0, 2)) 27 .map(grouped -> 28 GroupedObservable.from( 29 areas.get(grouped.getKey()) 30 .getOrElse("Unknown"), 31 grouped.map(Tuple2::_2) 32 ) 33 ) 34 .forEach(grouped -> grouped.forEach(number -> 35 out.println( 36 grouped.getKey() + ": " + number 37 ) 38 ) 39 ); 40 } 41 42 } Event streams 
 with RxJava: 
 reuse your lambdas! • highlighted code is the same as code used on Javaslang collection! • we are operating on potentially infinite stream, so groupBy returns Observable of GroupedObservables - a stream of streams of values grouped by key!
  • 147. Use cases of
 Reactive Extensions • Streams of events
  • 148. Use cases of
 Reactive Extensions • Streams of events • Parallel processing
  • 149. Use cases of
 Reactive Extensions • Streams of events • Parallel processing • Asynchronous programming
  • 150. Use cases of
 Reactive Extensions • Streams of events • Parallel processing • Asynchronous programming • Bonus: functional error handling
  • 151. Use cases of
 Reactive Extensions • Streams of events • Parallel processing • Asynchronous programming • Bonus: functional error handling • Bonus: reactive streams specification
  • 152. Functional Programming in Java: not needed, right?
  • 153. Functional Programming in Java: not needed, right? • Microservices need linear scalability on instance level, which is hard to achieve using thread-per-request model, asynchronous frameworks offer this 
 out-of-the-box
  • 154. Functional Programming in Java: not needed, right? • Microservices need linear scalability on instance level, which is hard to achieve using thread-per-request model, asynchronous frameworks offer this 
 out-of-the-box • Reactive, event-driven programming model has already been included into latest Java version - reactive streams interfaces made it to JDK9!
  • 155. Also - Spring 5: 1 @GetMapping("/accounts/{id}/alerts") 2 public Flux<Alert> getAccountAlerts(@PathVariable Long id) { 3 4 return this.repository.getAccount(id) 5 .flatMap(account -> 6 this.webClient 7 .perform(get("/alerts/{key}", account.getKey())) 8 .extract(bodyStream(Alert.class)) 9 ); 10 }
  • 156. And Vert.x: 1 server.requestStream() 2 .toObservable() 3 .subscribe(request -> 4 request.toObservable() 5 .lift(RxHelper.unmarshaller(MyPojo.class)) 6 .map(Marshaller::toMongoDocument) 7 .flatMap(jsonObject -> mongo.insertObservable(MY_POJOS, jsonObject)) 8 .subscribe( 9 () -> request.response() 10 .setStatusCode(200) 11 .end(), 12 err -> request.response() 13 .setStatusCode(500) 14 .end() 15 ) 16 );