KEMBAR78
Javaz. Functional design in Java 8. | PDF
JavazJavaz
Functional designFunctional design
in Java 8in Java 8
IntroIntro
All Java code can be found at Javaz
https://github.com/escalate42/Javaz
The emergence of native support for lambdas in Java 8
has opened the possibility to adapt the rich experience
of statically typed functional programming languages to
the Java world. So the Javaz appears.
finally!This presentation can be found at
https://slides.com/vadimdubs/javaz​
Common functionalCommon functional
programming patternsprogramming patterns
Functor
ApplicativeFunctor
Monad
First appeared in Haskell programing langugage
TypeclassesTypeclasses
First appeared in Haskell programing langugage
Is a sort of interface that defines some behavior
You can think of them kind of as Java interfaces
-- Typeclass definition with name Eq, type variable a
-- and function == which has two params of type a and
-- returns Bool
class Eq a where
eq :: a -> a -> Bool
-- Data Type definition (like Java enum in this case)
data TrafficLight = Red | Yellow | Green
-- Instance definition for TrafficLight data type and
-- Eq typeclass
instance Eq TrafficLight where
eq Red Red = True
eq Yellow Yellow = True
eq Green Green = True
eq _ _ = False
public interface Eq<A> {
public boolean eq(A other);
}
public final class TrafficLight implements Eq<TrafficLight> {
public static TrafficLight RED = new TrafficLight();
public static TrafficLight YELLOW = new TrafficLight();
public static TrafficLight GREEN = new TrafficLight();
private TrafficLight() {}
@Override
public boolean eq(TrafficLight other) {
return other == this;
}
}
FunctionFunction
@FunctionalInterface
interface Function<A, B> {
B apply(A a);
}
Function<A, B> function1 = Functions::function;
Function<A, B> function2 = a -> new B(a);
function :: a -> b
@FunctionalInterface
interface Function<A, B> {
B apply(A a);
}
Function<A, B> f;
Function<B, C> g;
static <A, B, C> Function<A, C> compose(
Function<A, B> ab, Function<B, C> bc
) {
return a -> bc.apply(ab.apply(a));
}
Function<A, C> h = compose(f, g);
f :: a -> b
g :: b -> c
. :: (a -> b) -> (b -> c) -> a -> c
f1 . f2 = x -> f2 (f1 x)
h :: a -> c
h = f . g
FunctorFunctor
for things that can be mapped over.
class Functor F where
fmap :: (a -> b) -> F a -> F b
data Maybe a = Just a | Nothing
FunctorFunctor
for things that can be mapped over.
class Functor F where
fmap :: (a -> b) -> F a -> F b
Applicative FunctorApplicative Functor
class (Functor F) => Applicative F where
pure :: a -> F a
(<*>) :: F (a -> b) -> F a -> F b
Applicative FunctorApplicative Functor
class (Functor F) => Applicative F where
pure :: a -> F a
(<*>) :: F (a -> b) -> F a -> F b
MonadMonad
class Monad M where
return :: a -> M a
(>>=) :: M a -> (a -> M b) -> M b
MonadMonad
class Monad M where
return :: a -> M a
(>>=) :: M a -> (a -> M b) -> M b
f :: a -> M a
g :: a -> M b
-- Bind function
(>>=) :: M a -> (a -> M b) -> M b
a -> (f a) >>= a -> (g a)
-- Same in term of types
-- (>>=) is the same as
-- composition of functions
(a -> M a) >>= (a -> M b)
-- Composition of functions
(a -> a) . (a -> b)
CommonCommon
implementationsimplementations
Collection - container for a group of
values
Option/Maybe​ - for optional values
Either - for results that either success or
failure
Future - for async computations
OptionOption
For optional values, typesafe way to avoid null and null-checks
Option<T> always is in one of two states:
Some<T> - simple container for value of type T
None<T> - represents absence of any value of type T
Javaz implementation
User auth(String l, String p);
Role getRole(User u);
Permissions getPermissions(Role r);
List<Partner> getPartners(Permissions p);
User user = auth("user", "password");
Role role = null;
Permissions permissions = null;
List<Partner> partners = new ArrayList<>();
if (user != null) {
role = getRole(user);
}
if (role != null) {
permissions = getPermissions(role);
}
if (permissions != null) {
partners.addAll(getPartners(permissions));
}
Function2<String, String, Option<User>> auth;
Function<User, Option<Role>> getRole;
Function<Role, Option<Permissions>> getPermissions;
Function<Permissions, List<Partner>> getPartners;
List<Partner> partners =
// trying to authenticate user
auth.apply("login", "password")
// trying to get Role for this
// user from service via http
.flatMap(getRole) // the same as >>=
// trying to load permissions
// from database
.flatMap(getPermissions)
// trying to load partners from
// another data source
.map(getPartners) // the same as fmap
.getOrElse(new ArrayList());
OptionalOptional
import static Optional.of;
import static Optional.empty;
final Optional<Integer> first = of(3);
final Optional<Integer> second = of(4);
final Optional<Integer> empty = empty();
// Optional is a functor and monad
first.map(i -> i * i) // Some(9)
empty.map(i -> i * i) // None
first.flatMap(f -> second.map(s -> f + s));
// Some(7)
first.flatMap(f -> empty.map(s -> f + s));
// None
Implementation from standard Java 8 library
EitherEither
For results that either success or failure, typesafe way to avoid
usege of exceptions.
Has no analogs in standard Java library.
Either<L, R> always is in one of two states:
Right<L, R> - container for value of type R
Left<L, R> - container for values of type L that represents some
failure
Javaz implementation
F2<String, String, Either<ErrorInfo, User>> auth;
F<User, Either<ErrorInfo, Role>> getRole;
F<Role, Either<ErrorInfo, Permissions>> getPermissions;
F<Permissions, List<Partner>> getPartners;
Either<ErrorInfo, List<Partner>> eitherPartners =
// trying to authenticate user
auth.apply("login", "password")
// trying to get Role for this
// user from service via http
.fmap(getRole)
// trying to load permissions
// from database
.fmap(getPermissions)
// trying to load partners from
// another data source
.map(getPartners);
eitherPartners.mapLeft(logger::error);
List<String> partnerNames = eitherPartners.foldRight(
new ArrayList(), partner -> partner.getName
)
StreamStream
final Stream<Integer> stream =
Arrays.asList(1, 2, 3, 4, 5).stream();
// Streams are functors
stream.map(i -> i + 1);
// [2, 3, 4, 5, 6]
stream.forEach(System.out::print);
// out > 12345
Implementation from standard Java 8 library
StreamStream
final Stream<Integer> stream
= Arrays.asList(1, 2, 3, 4, 5).stream();
// Streams are monads
stream.flatMap(
i -> Arrays.asList(i + 1, i + 2).stream()
);
// [2, 3, 3, 4, 4, 5, 5, 6, 6, 7]
Implementation from standard Java 8 library
StreamStream
Function<User, Stream<Permission>> permissionsByUser;
Function<Permission, Stream<Partner>> partnersByPermissions;
Stream<User> users = Arrays.asList(user1, user2).stream();
Set<Partners> availablePartners = users
.flatMap(permissionByUser)
// get all permissions of user 1 and user2
.distinct()
// left only unique items
.flatMap(partnersByPermissions)
// get all partners available through permissions
.collect(Collectors.toSet);
Implementation from standard Java 8 library
FutureFuture
Javaz implementation
Function2<String, String, Future<User>> auth;
Function<User, Future<Stream<User>>> getFriends;
Function<User, Stream<Group>> getGroups;
Future<User> user = auth.apply("login", "password");
Future<Stream<Group>> myGroups = user.map(getGroups)
Future<Stream<User>> friendsGroups = user
.flatMap(getFriends)
.map(Stream::flatMap(getGroups).distinct());
Future<Set<Group>> uniqueFriendsGroups = yieldFor(
myGroups, myFirends, (myGroups, firendsGroups) ->
friendsGroups.collect(toSet)
.removeAll(myGroups.collect(toSet))
)
uniqueFriendsGroups.get(100, TimeUnit.MILLISECONDS)
CompletableFutureCompletableFuture
Implementation from standard Java 8 library
final CompletableFuture<Integer> future =
CompletableFuture.supplyAsync(() -> 3 * 2);
// CompletableFuture is functor
future.thenApplyAsync(i -> i * i); // CompletableFuture(36)
future.handleAsync(
(val, exc) -> val != null ? val.toString() : ""
); // CompletableFuture("6")
future.thenAcceptAsync(System.out::println); // out > 6
// CompletableFuture is monad
future.thenComposeAsync(
i -> CompletableFuture.supplyAsync(() -> i * 2)
); // CompletableFuture(12)
Why should I care?Why should I care?
Simple complexity
Composability
Type safety
Unification
Javaz. Functional design in Java 8.

Javaz. Functional design in Java 8.

  • 1.
  • 2.
    IntroIntro All Java codecan be found at Javaz https://github.com/escalate42/Javaz The emergence of native support for lambdas in Java 8 has opened the possibility to adapt the rich experience of statically typed functional programming languages to the Java world. So the Javaz appears. finally!This presentation can be found at https://slides.com/vadimdubs/javaz​
  • 3.
    Common functionalCommon functional programmingpatternsprogramming patterns Functor ApplicativeFunctor Monad First appeared in Haskell programing langugage
  • 4.
    TypeclassesTypeclasses First appeared inHaskell programing langugage Is a sort of interface that defines some behavior You can think of them kind of as Java interfaces
  • 6.
    -- Typeclass definitionwith name Eq, type variable a -- and function == which has two params of type a and -- returns Bool class Eq a where eq :: a -> a -> Bool -- Data Type definition (like Java enum in this case) data TrafficLight = Red | Yellow | Green -- Instance definition for TrafficLight data type and -- Eq typeclass instance Eq TrafficLight where eq Red Red = True eq Yellow Yellow = True eq Green Green = True eq _ _ = False
  • 7.
    public interface Eq<A>{ public boolean eq(A other); } public final class TrafficLight implements Eq<TrafficLight> { public static TrafficLight RED = new TrafficLight(); public static TrafficLight YELLOW = new TrafficLight(); public static TrafficLight GREEN = new TrafficLight(); private TrafficLight() {} @Override public boolean eq(TrafficLight other) { return other == this; } }
  • 8.
    FunctionFunction @FunctionalInterface interface Function<A, B>{ B apply(A a); } Function<A, B> function1 = Functions::function; Function<A, B> function2 = a -> new B(a);
  • 9.
  • 10.
    @FunctionalInterface interface Function<A, B>{ B apply(A a); } Function<A, B> f; Function<B, C> g; static <A, B, C> Function<A, C> compose( Function<A, B> ab, Function<B, C> bc ) { return a -> bc.apply(ab.apply(a)); } Function<A, C> h = compose(f, g);
  • 11.
    f :: a-> b g :: b -> c . :: (a -> b) -> (b -> c) -> a -> c f1 . f2 = x -> f2 (f1 x) h :: a -> c h = f . g
  • 12.
    FunctorFunctor for things thatcan be mapped over. class Functor F where fmap :: (a -> b) -> F a -> F b
  • 16.
    data Maybe a= Just a | Nothing
  • 23.
    FunctorFunctor for things thatcan be mapped over. class Functor F where fmap :: (a -> b) -> F a -> F b
  • 24.
    Applicative FunctorApplicative Functor class(Functor F) => Applicative F where pure :: a -> F a (<*>) :: F (a -> b) -> F a -> F b
  • 29.
    Applicative FunctorApplicative Functor class(Functor F) => Applicative F where pure :: a -> F a (<*>) :: F (a -> b) -> F a -> F b
  • 30.
    MonadMonad class Monad Mwhere return :: a -> M a (>>=) :: M a -> (a -> M b) -> M b
  • 37.
    MonadMonad class Monad Mwhere return :: a -> M a (>>=) :: M a -> (a -> M b) -> M b
  • 38.
    f :: a-> M a g :: a -> M b -- Bind function (>>=) :: M a -> (a -> M b) -> M b a -> (f a) >>= a -> (g a) -- Same in term of types -- (>>=) is the same as -- composition of functions (a -> M a) >>= (a -> M b) -- Composition of functions (a -> a) . (a -> b)
  • 40.
    CommonCommon implementationsimplementations Collection - containerfor a group of values Option/Maybe​ - for optional values Either - for results that either success or failure Future - for async computations
  • 41.
    OptionOption For optional values,typesafe way to avoid null and null-checks Option<T> always is in one of two states: Some<T> - simple container for value of type T None<T> - represents absence of any value of type T Javaz implementation
  • 42.
    User auth(String l,String p); Role getRole(User u); Permissions getPermissions(Role r); List<Partner> getPartners(Permissions p); User user = auth("user", "password"); Role role = null; Permissions permissions = null; List<Partner> partners = new ArrayList<>(); if (user != null) { role = getRole(user); } if (role != null) { permissions = getPermissions(role); } if (permissions != null) { partners.addAll(getPartners(permissions)); }
  • 43.
    Function2<String, String, Option<User>>auth; Function<User, Option<Role>> getRole; Function<Role, Option<Permissions>> getPermissions; Function<Permissions, List<Partner>> getPartners; List<Partner> partners = // trying to authenticate user auth.apply("login", "password") // trying to get Role for this // user from service via http .flatMap(getRole) // the same as >>= // trying to load permissions // from database .flatMap(getPermissions) // trying to load partners from // another data source .map(getPartners) // the same as fmap .getOrElse(new ArrayList());
  • 44.
    OptionalOptional import static Optional.of; importstatic Optional.empty; final Optional<Integer> first = of(3); final Optional<Integer> second = of(4); final Optional<Integer> empty = empty(); // Optional is a functor and monad first.map(i -> i * i) // Some(9) empty.map(i -> i * i) // None first.flatMap(f -> second.map(s -> f + s)); // Some(7) first.flatMap(f -> empty.map(s -> f + s)); // None Implementation from standard Java 8 library
  • 45.
    EitherEither For results thateither success or failure, typesafe way to avoid usege of exceptions. Has no analogs in standard Java library. Either<L, R> always is in one of two states: Right<L, R> - container for value of type R Left<L, R> - container for values of type L that represents some failure Javaz implementation
  • 46.
    F2<String, String, Either<ErrorInfo,User>> auth; F<User, Either<ErrorInfo, Role>> getRole; F<Role, Either<ErrorInfo, Permissions>> getPermissions; F<Permissions, List<Partner>> getPartners; Either<ErrorInfo, List<Partner>> eitherPartners = // trying to authenticate user auth.apply("login", "password") // trying to get Role for this // user from service via http .fmap(getRole) // trying to load permissions // from database .fmap(getPermissions) // trying to load partners from // another data source .map(getPartners); eitherPartners.mapLeft(logger::error); List<String> partnerNames = eitherPartners.foldRight( new ArrayList(), partner -> partner.getName )
  • 47.
    StreamStream final Stream<Integer> stream= Arrays.asList(1, 2, 3, 4, 5).stream(); // Streams are functors stream.map(i -> i + 1); // [2, 3, 4, 5, 6] stream.forEach(System.out::print); // out > 12345 Implementation from standard Java 8 library
  • 48.
    StreamStream final Stream<Integer> stream =Arrays.asList(1, 2, 3, 4, 5).stream(); // Streams are monads stream.flatMap( i -> Arrays.asList(i + 1, i + 2).stream() ); // [2, 3, 3, 4, 4, 5, 5, 6, 6, 7] Implementation from standard Java 8 library
  • 49.
    StreamStream Function<User, Stream<Permission>> permissionsByUser; Function<Permission,Stream<Partner>> partnersByPermissions; Stream<User> users = Arrays.asList(user1, user2).stream(); Set<Partners> availablePartners = users .flatMap(permissionByUser) // get all permissions of user 1 and user2 .distinct() // left only unique items .flatMap(partnersByPermissions) // get all partners available through permissions .collect(Collectors.toSet); Implementation from standard Java 8 library
  • 50.
    FutureFuture Javaz implementation Function2<String, String,Future<User>> auth; Function<User, Future<Stream<User>>> getFriends; Function<User, Stream<Group>> getGroups; Future<User> user = auth.apply("login", "password"); Future<Stream<Group>> myGroups = user.map(getGroups) Future<Stream<User>> friendsGroups = user .flatMap(getFriends) .map(Stream::flatMap(getGroups).distinct()); Future<Set<Group>> uniqueFriendsGroups = yieldFor( myGroups, myFirends, (myGroups, firendsGroups) -> friendsGroups.collect(toSet) .removeAll(myGroups.collect(toSet)) ) uniqueFriendsGroups.get(100, TimeUnit.MILLISECONDS)
  • 51.
    CompletableFutureCompletableFuture Implementation from standardJava 8 library final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 3 * 2); // CompletableFuture is functor future.thenApplyAsync(i -> i * i); // CompletableFuture(36) future.handleAsync( (val, exc) -> val != null ? val.toString() : "" ); // CompletableFuture("6") future.thenAcceptAsync(System.out::println); // out > 6 // CompletableFuture is monad future.thenComposeAsync( i -> CompletableFuture.supplyAsync(() -> i * 2) ); // CompletableFuture(12)
  • 52.
    Why should Icare?Why should I care? Simple complexity Composability Type safety Unification