Functional Java,
a practical example
HELLO!
I am Marian Wamsiedel
I work as a Java developer. You can find me at
marian.wamsiedel@gmail.com
2
Motivation
As always, the code examples are rather
naive, they are not meant to be used without
changes in a real life scenario.
Running code examples are available in a
github repository.
3
Functional Java
Java was designed as an object oriented programming
language, but, starting with version 8, it offers also
support for functional programming.
The choice between one of the two programming
paradigms is currently a discussed topic.
I present here an object oriented and some functional
solutions to implement a simple programming task.
The challenge:
Your company is building vehicles that need to be controlled remote by sending
some vocal commands.
The commands look like: “start”, “move forward”, “move left”, “stop” and so on.
Each vehicle implements an interface, that you design. The vehicle is being moved
by calling the interface methods, like: vehicle.moveForward(), or vehicle.stop().
A third-party library takes care of sending the vocal commands to a command
centre
The task is to write the code that runs the vocal commands on a vehicle.
The solution to be implemented
4
One problem, three solutions
5
Object
oriented
Pure
functional
Functional
with
effects
The object oriented
approach
Think solid
6
1
Object oriented approach
7
The Vehicle interface could contain methods like:
void wakeUp();
void moveForward(Distance distance);
void moveLeft(Distance distance);
void moveRight(Distance distance);
void stop();
Coordinate currentPosition();
Each method would throw a runtime exception if something goes wrong.
Object oriented approach
8
The vocal commands could be modelled as Command classes, each one exposing an
execute() method. We end up with mappings like these:
“move forward 6 meter” → new MoveForwardCommand(vehicle, Distance.meter(6))
“move left 3 meter” → new MoveLeftCommand(vehicle, Distance.meter(3))
“stop” → new StopCommand(vehicle)
A list of commands can be executed by iterating over it and calling the execute() method for
each of its items.
Some form of exception handling is expected, for instance: “logging the root cause and the
current vehicle position”.
Object oriented approach
9
Optimization: since the vehicle needs to be started before any move and stopped after the
ride completes, the application should take care automatically of start-stop moves. This can
be done using the template pattern:
Any ride consists of three types of actions: before raid (preparation), main ride and after ride
(clean up). A template superclass implements the before and after functionality and each
ride class provides the mainRide() method, that contains the specific moves.
Executable code examples in this repository:
https://github.com/mw1980/oofunctionalexample the package “oo”
Object oriented approach
10
The code for the vehicle ride would then look like:
new VehicleRide(
new MoveForwardCommand(vehicle, Distance.ONE_METER),
new MoveLeftCommand(vehicle, Distance.inch(2)),
new MoveRightCommand(vehicle, Distance.THREE_METER)
).startRide()
The VehicleRide class implements the main ride logic for the commands received as
parameter, while its parent, the AbstractTemplateRide class takes care of start – stop
operations.
https://github.com/mw1980/oofunctionalexample , the package “oo”
One problem, three solutions
11
Pure
functional
Object
oriented
Functional
with
effects
A pure functional
approach
The joy of purity...
12
2
Pure functional approach
13
The functional programming has other goals, like referential transparency,
immutability and isolation of side effects.
Immutability is a central concept of the functional programming. Therefore the
methods that receive a parameter and return “void” look suspicious, because they
probably modify the state of their input parameter.
For instance, the move methods from the “oo” implementation would modify the
vehicle coordinates, fuel status, temperature and so on.
Therefore the Vehicle interface methods would rather return a new vehicle
instance, instead of void. For example:
Vehicle moveForward(Distance distance)
Vehicle stop()
Pure functional approach
14
The command classes from the object oriented implementation would be replaced
by some functions:
MOVE_FORWARD = distance-> vehicle -> vehicle.moveForward(distance)
MOVE_LEFT = distance-> vehicle -> vehicle.moveLeft(distance)
MOVE_RIGHT = distance-> vehicle -> vehicle.moveRight(distance)
STOP = Vehicle::stop
START = Vehicle::wakeUp
If the code looks weird, read more about currying here.
Pure functional approach
15
By fixing the distance in the above function definitions, the vehicle moves become functions
that depend only on the vehicle (unary operators):
UnaryOperator<Vehicle> moveLeft3 = MOVE_LEFT.apply(Distance.THREE_METER)
UnaryOperator<Vehicle> moveRight10 = MOVE_RIGHT.apply(Distance.TEN_METER)
UnaryOperator<Vehicle> moveForward13 = MOVE_FORWARD.apply(Distance.inch(13))
A simple ride would look like this:
START.andThen(moveLeft3).andThen(moveRight10).andThen(moveForward13)
.andThen(STOP).apply(vehicle)
Pure functional approach
16
The solution is very expressive, but still kind of verbose, requiring a new “andThen” call for
each move. Some functional patterns can make the code even compacter:
The monoid
The term comes from mathematics and it means a semi group with unity element.
To keep things simple, a monoid is a sequence of elements of some type: A, that support an
operation op : (A, A) → A.
There is also a special element of type A (the “unity”), that has no effect in the op
computation: op (unity, a) = op(a, unity) = a;
Read more about it here.
Pure functional approach
17
Examples:
- The strings, having concatenation as operation and the
empty string as unity element.
- The integer numbers, having the sum (the addition) as
operation and zero as unity element.
Since the functions are first class citizens in the
functional programming world, the A elements can be
functions, like the unary operators defined above and the
operation “op” can be the composition of functions:
Pure functional approach
18
a1 is “f1 : Vehicle → Vehicle”,
a2 is “f2 : Vehicle → Vehicle”,
op(a1, a2) is the composition of f1 and f2, also an unary operator for vehicles.
op(a1, a2) = a2 ◦ a1, or more detailed:
op(f1, f2) (vehicle) = f2.apply(f1.apply(vehicle))
The unity element would be the function that simply returns its input parameter:
unity(vehicle) = vehicle, for any vehicle object
Pure functional approach
19
Any monoid supports folding operations, by applying the
operation “op”:
- on unity element and on monoids first element to produce
a result
- then on the result and on monoids second element
- and so on, to end up with a single element.
Example: The folding of a sequence of integers, with
addition as operation and unity element zero would
produce a single value that is the sum of all integers in the
sequence.
Pure functional approach
20
Since the Java 8 Streams API implements already the folding functionality, the sequence of the
vehicle moves can be modelled also this way:
allMoves = Stream.of(moveLeft3, moveRight10, moveForward13)
.reduce(
UnaryOperator.identity(),
(first, second) -> v -> second.apply(first.apply(v))
)
allMoves.apply(vehicle)
https://github.com/mw1980/oofunctionalexample , package functional/pure
Pure functional approach
21
The prefixing and suffixing of some vehicle moves could be modelled as a function, that
replaces the template pattern. The ride function simply wraps a vehicle move between start
and stop actions.
ride: unaryVehicleOperator → start ◦ unaryVehicleOperator ◦ stop.
The code:
Function<UnaryOperator<Vehicle>, UnaryOperator<Vehicle>>
ride = f -> vehicle -> STOP.apply(f.apply(START.apply(vehicle)));
The code that moves the vehicle and returns its coordinate will look like:
ride.apply(allMoves).apply(vehicleInstance).currentPosition();
https://github.com/mw1980/oofunctionalexample , package functional/pure
One problem, three solutions
22
Functional
with
effects
Object
oriented
Pure
functional
Real world
functional approach
Consider also side effects
23
3
Real world functional approach
24
We ignored the potential exceptions so far. They are considered in the functional programming
impure and therefore not supported. The exceptions are possible effects that hurt the
referential transparency of the system and should be isolated from the business logic
implementation.
Throwing and catching exceptions is seen as a glorified form of the “go to” statement, that
should be avoided.
The functional programming way to handle an exception is to wrap the suspect code block in
another component, like a Try, or an IO wrapper class.
The simple presence of Try, or IO components signalizes that the code might deal with side
effects, isolating the pure functional code from the rest.
Real world functional approach
▰ Lazy Try blocks
▰ Simple Try blocks
▰ Try with errors
25
Real world functional approach
26
In the context of vehicle operators, the try component could look like this:
class LazyTry<T> {
//injected in the constructor
private final UnaryOperator<T> f;
public T execute(final T t) {
try {f.apply(t);} // use try – catch only here
catch (RuntimeException exception) { // handle the error case }
}}
The Try class is a generic, lazy evaluated and reusable component.
Real world functional approach
27
The Try blocks can be composed, if they implement a
combine method, like “andThen”
LazyTry.to[f].andThen[g] = LazyTry.to[f ◦ g];
The operation can be repeated:
LazyTry.to[f1].andThen[f2] … andThen[fn] = LazyTry.to[f1 ◦
f2 ◦ … ◦ fn]
public LazyTry<T> andThen(UnaryOperator<T> after)
{
return
new LazyTry<>(t -> after.apply(f.apply(t)));
}
Real world functional approach
28
The vehicle moves could look like:
LazyTry.to(Vehicle::wakeUp)
.andThen(v -> v.moveLeft(FIVE_METER))
.andThen(v -> v.moveForward(THREE_METER))
...
.andThen(Vehicle::stop)
.onError(exception -> System.out.println(“err:”+ exception.getMessage()))
.execute(someVehicleInstance)
Real world functional approach
29
A sequence of lazy try blocks can be seen as a monoid, with:
- identity element = LazyTry.to( UnaryOperator.identity() )
- the lazyTryComposition(LazyTry.to[f], LazyTry.to[g]) = LazyTry.to[f◦g].
It is possible to fold on a sequence of try elements, using the Java 8 streams API. If the vehicle
moves are encapsulated in LazyTry instances, the code for the vehicle ride looks like:
Stream.of(LazyTry.of(firstVehicleMove), … , LazyTry.of(lastVehicleMove))
.reduce(identityElement, lazyTryComposition)
.execute(someVehicle);
The online repository contains an example:
https://github.com/mw1980/oofunctionalexample/ package functional/effects
Real world functional approach
▰ Lazy Try blocks
▰ Simple Try blocks
▰ Try with errors
30
Real world functional approach
31
The expressions that generate effects can also be initialized eagerly. The standard way is to
use a simple Try<T> block, that contains already the evaluated value of type T.
The Try class can have two subclasses: Success and Failure, that cover the successful
execution, or the operation failure.
The Try objects would be instantiated in a factory method:
static <T> Try<T> of(Supplier<T> supplier) {
try {
return new Success<>(supplier.get());
} catch (Exception exception) {
return new Failure<>(exception);
}
}
Real world functional approach
32
The Try<T> class could expose standard “map” and “flat map” methods, that lift some
operations on T type in the Try context:
public interface Try<T> {
...
Try<T> map(UnaryOperator<T> f);
Try<T> flatMap(Function<T, Try<T>> f);
…
}
Real world functional approach
33
The vehicle interface could look like:
public interface Vehicle {
Try<Vehicle> wakeUp();
Try<Vehicle> moveForward(Distance distance);
Try<Vehicle> moveLeft(Distance distance);
Try<Vehicle> moveRight(Distance distance);
Try<Vehicle> stop();
}
Real world functional approach
34
The vehicle moves can be modelled this way:
MOVE_FORWARD = distance -> vehicle -> vehicle.moveForward(distance);
MOVE_LEFT = distance -> vehicle -> vehicle.moveLeft(distance);
START = Vehicle::wakeUp;
STOP = Vehicle::stop;
Try.<Vehicle>of(Vehicle.Default::new)
.flatMap(START)
.flatMap(MOVE_FORWARD.apply(Distance.THREE_METER))
.flatMap(MOVE_LEFT.apply(Distance.FIVE_METER))
.flatMap(MOVE_RIGHT.apply(Distance.TEN_METER))
.flatMap(STOP);
The online repository contains an example.
https://github.com/mw1980/oofunctionalexample/ package “functional/effects/basic”
Real world functional approach
▰ Lazy Try blocks
▰ Simple Try blocks
▰ Try with errors
35
Real world functional approach
36
In some cases it is important to return the exception that might occur. The system could be
required to react differently, according to the exception type. The class Either can be used to
store also the potential error:
public class Either<T, V> {
//injected in the constructor, mutual exclusive
private final T left; //exception comes here, by convention
private final V right;
public static <T, V> Either<T, V> withLeftValue(final T value) {…}
public static <T, V> Either<T, V> withRightValue(final V value) {…}
}
Real world functional approach
37
The Try class could be rewritten to consider also exceptions:
public class TryWithError<T, U> {
private final Function<T, U> f;
public Either<RuntimeException, U> execute(T t) {
try { return Either.withRightValue(f.apply(t));}
catch (RuntimeException exception) {
return Either.withLeftValue(
new RuntimeException(“error message”, exception)
);
}}}
Real world functional approach
38
The code that performs the vehicle actions and returns also the exceptions that might occur
would then look like:
Either<RuntimeException, Vehicle> vehicleMoveResult =
TryWithError.to(Vehicle::wakeUp)
.andThen(v -> v.moveLeft(FIVE_METER))
...
.andThen(Vehicle::stop)
.execute(someVehicleInstance)
Real world functional approach
39
OO against FP, my two cents:
The functional programming:
+ extremely compact
+ handles the exceptions gracefully
+ truly reusable design patterns
- abstract
- requires more discipline
- it gets complex if it handles simultaneously more concerns, like handling exceptions and
missing return values
Real world functional approach
40
OO against FP, my two cents:
Object oriented programming:
+ easier to understand
+ easier to extend
+ its design patterns are a great communications instrument
+ it is trivial to write unit tests
+ the “Gof” design patterns, like Command and Template communicate well the code
intention. They are well known and generally accepted by the Java community
Real world functional approach
41
OO against FP, my two cents:
Object oriented programming:
- explosion of classes
- code verbosity
- difficult to maintain the overview when using template classes, especially if the class
inheritance hierarchy gets long
Read more
42
More documentation:
Functional and Reactive Domain Modeling (Debasish Gosh), Manning 2016
Functional Programming in Java (Pierre-Yves Saumont), Manning 2016
Vavr: http://www.vavr.io/
Eta lang: https://eta-lang.org/
Referential transparency: https://en.wikipedia.org/wiki/Referential_transparency
Currying:
https://hackernoon.com/functional-programming-paradigms-in-modern-javascript-currying-565
2e489cce8
Monoids: https://medium.com/@sjsyrek/five-minutes-to-monoid-fe6f364d0bba
CREDITS
Graphical content:
▰ Presentation template by SlidesCarnival
▰ Photographs by Startup Stock Photos
43

Design functional solutions in Java, a practical example

  • 1.
  • 2.
    HELLO! I am MarianWamsiedel I work as a Java developer. You can find me at marian.wamsiedel@gmail.com 2
  • 3.
    Motivation As always, thecode examples are rather naive, they are not meant to be used without changes in a real life scenario. Running code examples are available in a github repository. 3 Functional Java Java was designed as an object oriented programming language, but, starting with version 8, it offers also support for functional programming. The choice between one of the two programming paradigms is currently a discussed topic. I present here an object oriented and some functional solutions to implement a simple programming task.
  • 4.
    The challenge: Your companyis building vehicles that need to be controlled remote by sending some vocal commands. The commands look like: “start”, “move forward”, “move left”, “stop” and so on. Each vehicle implements an interface, that you design. The vehicle is being moved by calling the interface methods, like: vehicle.moveForward(), or vehicle.stop(). A third-party library takes care of sending the vocal commands to a command centre The task is to write the code that runs the vocal commands on a vehicle. The solution to be implemented 4
  • 5.
    One problem, threesolutions 5 Object oriented Pure functional Functional with effects
  • 6.
  • 7.
    Object oriented approach 7 TheVehicle interface could contain methods like: void wakeUp(); void moveForward(Distance distance); void moveLeft(Distance distance); void moveRight(Distance distance); void stop(); Coordinate currentPosition(); Each method would throw a runtime exception if something goes wrong.
  • 8.
    Object oriented approach 8 Thevocal commands could be modelled as Command classes, each one exposing an execute() method. We end up with mappings like these: “move forward 6 meter” → new MoveForwardCommand(vehicle, Distance.meter(6)) “move left 3 meter” → new MoveLeftCommand(vehicle, Distance.meter(3)) “stop” → new StopCommand(vehicle) A list of commands can be executed by iterating over it and calling the execute() method for each of its items. Some form of exception handling is expected, for instance: “logging the root cause and the current vehicle position”.
  • 9.
    Object oriented approach 9 Optimization:since the vehicle needs to be started before any move and stopped after the ride completes, the application should take care automatically of start-stop moves. This can be done using the template pattern: Any ride consists of three types of actions: before raid (preparation), main ride and after ride (clean up). A template superclass implements the before and after functionality and each ride class provides the mainRide() method, that contains the specific moves. Executable code examples in this repository: https://github.com/mw1980/oofunctionalexample the package “oo”
  • 10.
    Object oriented approach 10 Thecode for the vehicle ride would then look like: new VehicleRide( new MoveForwardCommand(vehicle, Distance.ONE_METER), new MoveLeftCommand(vehicle, Distance.inch(2)), new MoveRightCommand(vehicle, Distance.THREE_METER) ).startRide() The VehicleRide class implements the main ride logic for the commands received as parameter, while its parent, the AbstractTemplateRide class takes care of start – stop operations. https://github.com/mw1980/oofunctionalexample , the package “oo”
  • 11.
    One problem, threesolutions 11 Pure functional Object oriented Functional with effects
  • 12.
    A pure functional approach Thejoy of purity... 12 2
  • 13.
    Pure functional approach 13 Thefunctional programming has other goals, like referential transparency, immutability and isolation of side effects. Immutability is a central concept of the functional programming. Therefore the methods that receive a parameter and return “void” look suspicious, because they probably modify the state of their input parameter. For instance, the move methods from the “oo” implementation would modify the vehicle coordinates, fuel status, temperature and so on. Therefore the Vehicle interface methods would rather return a new vehicle instance, instead of void. For example: Vehicle moveForward(Distance distance) Vehicle stop()
  • 14.
    Pure functional approach 14 Thecommand classes from the object oriented implementation would be replaced by some functions: MOVE_FORWARD = distance-> vehicle -> vehicle.moveForward(distance) MOVE_LEFT = distance-> vehicle -> vehicle.moveLeft(distance) MOVE_RIGHT = distance-> vehicle -> vehicle.moveRight(distance) STOP = Vehicle::stop START = Vehicle::wakeUp If the code looks weird, read more about currying here.
  • 15.
    Pure functional approach 15 Byfixing the distance in the above function definitions, the vehicle moves become functions that depend only on the vehicle (unary operators): UnaryOperator<Vehicle> moveLeft3 = MOVE_LEFT.apply(Distance.THREE_METER) UnaryOperator<Vehicle> moveRight10 = MOVE_RIGHT.apply(Distance.TEN_METER) UnaryOperator<Vehicle> moveForward13 = MOVE_FORWARD.apply(Distance.inch(13)) A simple ride would look like this: START.andThen(moveLeft3).andThen(moveRight10).andThen(moveForward13) .andThen(STOP).apply(vehicle)
  • 16.
    Pure functional approach 16 Thesolution is very expressive, but still kind of verbose, requiring a new “andThen” call for each move. Some functional patterns can make the code even compacter: The monoid The term comes from mathematics and it means a semi group with unity element. To keep things simple, a monoid is a sequence of elements of some type: A, that support an operation op : (A, A) → A. There is also a special element of type A (the “unity”), that has no effect in the op computation: op (unity, a) = op(a, unity) = a; Read more about it here.
  • 17.
    Pure functional approach 17 Examples: -The strings, having concatenation as operation and the empty string as unity element. - The integer numbers, having the sum (the addition) as operation and zero as unity element. Since the functions are first class citizens in the functional programming world, the A elements can be functions, like the unary operators defined above and the operation “op” can be the composition of functions:
  • 18.
    Pure functional approach 18 a1is “f1 : Vehicle → Vehicle”, a2 is “f2 : Vehicle → Vehicle”, op(a1, a2) is the composition of f1 and f2, also an unary operator for vehicles. op(a1, a2) = a2 ◦ a1, or more detailed: op(f1, f2) (vehicle) = f2.apply(f1.apply(vehicle)) The unity element would be the function that simply returns its input parameter: unity(vehicle) = vehicle, for any vehicle object
  • 19.
    Pure functional approach 19 Anymonoid supports folding operations, by applying the operation “op”: - on unity element and on monoids first element to produce a result - then on the result and on monoids second element - and so on, to end up with a single element. Example: The folding of a sequence of integers, with addition as operation and unity element zero would produce a single value that is the sum of all integers in the sequence.
  • 20.
    Pure functional approach 20 Sincethe Java 8 Streams API implements already the folding functionality, the sequence of the vehicle moves can be modelled also this way: allMoves = Stream.of(moveLeft3, moveRight10, moveForward13) .reduce( UnaryOperator.identity(), (first, second) -> v -> second.apply(first.apply(v)) ) allMoves.apply(vehicle) https://github.com/mw1980/oofunctionalexample , package functional/pure
  • 21.
    Pure functional approach 21 Theprefixing and suffixing of some vehicle moves could be modelled as a function, that replaces the template pattern. The ride function simply wraps a vehicle move between start and stop actions. ride: unaryVehicleOperator → start ◦ unaryVehicleOperator ◦ stop. The code: Function<UnaryOperator<Vehicle>, UnaryOperator<Vehicle>> ride = f -> vehicle -> STOP.apply(f.apply(START.apply(vehicle))); The code that moves the vehicle and returns its coordinate will look like: ride.apply(allMoves).apply(vehicleInstance).currentPosition(); https://github.com/mw1980/oofunctionalexample , package functional/pure
  • 22.
    One problem, threesolutions 22 Functional with effects Object oriented Pure functional
  • 23.
  • 24.
    Real world functionalapproach 24 We ignored the potential exceptions so far. They are considered in the functional programming impure and therefore not supported. The exceptions are possible effects that hurt the referential transparency of the system and should be isolated from the business logic implementation. Throwing and catching exceptions is seen as a glorified form of the “go to” statement, that should be avoided. The functional programming way to handle an exception is to wrap the suspect code block in another component, like a Try, or an IO wrapper class. The simple presence of Try, or IO components signalizes that the code might deal with side effects, isolating the pure functional code from the rest.
  • 25.
    Real world functionalapproach ▰ Lazy Try blocks ▰ Simple Try blocks ▰ Try with errors 25
  • 26.
    Real world functionalapproach 26 In the context of vehicle operators, the try component could look like this: class LazyTry<T> { //injected in the constructor private final UnaryOperator<T> f; public T execute(final T t) { try {f.apply(t);} // use try – catch only here catch (RuntimeException exception) { // handle the error case } }} The Try class is a generic, lazy evaluated and reusable component.
  • 27.
    Real world functionalapproach 27 The Try blocks can be composed, if they implement a combine method, like “andThen” LazyTry.to[f].andThen[g] = LazyTry.to[f ◦ g]; The operation can be repeated: LazyTry.to[f1].andThen[f2] … andThen[fn] = LazyTry.to[f1 ◦ f2 ◦ … ◦ fn] public LazyTry<T> andThen(UnaryOperator<T> after) { return new LazyTry<>(t -> after.apply(f.apply(t))); }
  • 28.
    Real world functionalapproach 28 The vehicle moves could look like: LazyTry.to(Vehicle::wakeUp) .andThen(v -> v.moveLeft(FIVE_METER)) .andThen(v -> v.moveForward(THREE_METER)) ... .andThen(Vehicle::stop) .onError(exception -> System.out.println(“err:”+ exception.getMessage())) .execute(someVehicleInstance)
  • 29.
    Real world functionalapproach 29 A sequence of lazy try blocks can be seen as a monoid, with: - identity element = LazyTry.to( UnaryOperator.identity() ) - the lazyTryComposition(LazyTry.to[f], LazyTry.to[g]) = LazyTry.to[f◦g]. It is possible to fold on a sequence of try elements, using the Java 8 streams API. If the vehicle moves are encapsulated in LazyTry instances, the code for the vehicle ride looks like: Stream.of(LazyTry.of(firstVehicleMove), … , LazyTry.of(lastVehicleMove)) .reduce(identityElement, lazyTryComposition) .execute(someVehicle); The online repository contains an example: https://github.com/mw1980/oofunctionalexample/ package functional/effects
  • 30.
    Real world functionalapproach ▰ Lazy Try blocks ▰ Simple Try blocks ▰ Try with errors 30
  • 31.
    Real world functionalapproach 31 The expressions that generate effects can also be initialized eagerly. The standard way is to use a simple Try<T> block, that contains already the evaluated value of type T. The Try class can have two subclasses: Success and Failure, that cover the successful execution, or the operation failure. The Try objects would be instantiated in a factory method: static <T> Try<T> of(Supplier<T> supplier) { try { return new Success<>(supplier.get()); } catch (Exception exception) { return new Failure<>(exception); } }
  • 32.
    Real world functionalapproach 32 The Try<T> class could expose standard “map” and “flat map” methods, that lift some operations on T type in the Try context: public interface Try<T> { ... Try<T> map(UnaryOperator<T> f); Try<T> flatMap(Function<T, Try<T>> f); … }
  • 33.
    Real world functionalapproach 33 The vehicle interface could look like: public interface Vehicle { Try<Vehicle> wakeUp(); Try<Vehicle> moveForward(Distance distance); Try<Vehicle> moveLeft(Distance distance); Try<Vehicle> moveRight(Distance distance); Try<Vehicle> stop(); }
  • 34.
    Real world functionalapproach 34 The vehicle moves can be modelled this way: MOVE_FORWARD = distance -> vehicle -> vehicle.moveForward(distance); MOVE_LEFT = distance -> vehicle -> vehicle.moveLeft(distance); START = Vehicle::wakeUp; STOP = Vehicle::stop; Try.<Vehicle>of(Vehicle.Default::new) .flatMap(START) .flatMap(MOVE_FORWARD.apply(Distance.THREE_METER)) .flatMap(MOVE_LEFT.apply(Distance.FIVE_METER)) .flatMap(MOVE_RIGHT.apply(Distance.TEN_METER)) .flatMap(STOP); The online repository contains an example. https://github.com/mw1980/oofunctionalexample/ package “functional/effects/basic”
  • 35.
    Real world functionalapproach ▰ Lazy Try blocks ▰ Simple Try blocks ▰ Try with errors 35
  • 36.
    Real world functionalapproach 36 In some cases it is important to return the exception that might occur. The system could be required to react differently, according to the exception type. The class Either can be used to store also the potential error: public class Either<T, V> { //injected in the constructor, mutual exclusive private final T left; //exception comes here, by convention private final V right; public static <T, V> Either<T, V> withLeftValue(final T value) {…} public static <T, V> Either<T, V> withRightValue(final V value) {…} }
  • 37.
    Real world functionalapproach 37 The Try class could be rewritten to consider also exceptions: public class TryWithError<T, U> { private final Function<T, U> f; public Either<RuntimeException, U> execute(T t) { try { return Either.withRightValue(f.apply(t));} catch (RuntimeException exception) { return Either.withLeftValue( new RuntimeException(“error message”, exception) ); }}}
  • 38.
    Real world functionalapproach 38 The code that performs the vehicle actions and returns also the exceptions that might occur would then look like: Either<RuntimeException, Vehicle> vehicleMoveResult = TryWithError.to(Vehicle::wakeUp) .andThen(v -> v.moveLeft(FIVE_METER)) ... .andThen(Vehicle::stop) .execute(someVehicleInstance)
  • 39.
    Real world functionalapproach 39 OO against FP, my two cents: The functional programming: + extremely compact + handles the exceptions gracefully + truly reusable design patterns - abstract - requires more discipline - it gets complex if it handles simultaneously more concerns, like handling exceptions and missing return values
  • 40.
    Real world functionalapproach 40 OO against FP, my two cents: Object oriented programming: + easier to understand + easier to extend + its design patterns are a great communications instrument + it is trivial to write unit tests + the “Gof” design patterns, like Command and Template communicate well the code intention. They are well known and generally accepted by the Java community
  • 41.
    Real world functionalapproach 41 OO against FP, my two cents: Object oriented programming: - explosion of classes - code verbosity - difficult to maintain the overview when using template classes, especially if the class inheritance hierarchy gets long
  • 42.
    Read more 42 More documentation: Functionaland Reactive Domain Modeling (Debasish Gosh), Manning 2016 Functional Programming in Java (Pierre-Yves Saumont), Manning 2016 Vavr: http://www.vavr.io/ Eta lang: https://eta-lang.org/ Referential transparency: https://en.wikipedia.org/wiki/Referential_transparency Currying: https://hackernoon.com/functional-programming-paradigms-in-modern-javascript-currying-565 2e489cce8 Monoids: https://medium.com/@sjsyrek/five-minutes-to-monoid-fe6f364d0bba
  • 43.
    CREDITS Graphical content: ▰ Presentationtemplate by SlidesCarnival ▰ Photographs by Startup Stock Photos 43