53
Javaz Javaz Functional design Functional design in Java 8 in Java 8

Javaz. Functional design in Java 8

Embed Size (px)

Citation preview

JavazJavazFunctional designFunctional design

in Java 8in Java 8

IntroIntro

All Java code can be found at Javazhttps://github.com/escalate42/Javaz

The emergence of native support for lambdas in Java 8has opened the possibility to adapt the rich experienceof statically typed functional programming languages tothe Java world. So the Javaz appears.

finally!This presentation can be found athttps://slides.com/vadimdubs/javaz

Common functionalCommon functionalprogramming patternsprogramming patterns

FunctorApplicativeFunctorMonad

First appeared in Haskell programing langugage

TypeclassesTypeclasses

First appeared in Haskell programing langugageIs a sort of interface that defines some behaviorYou 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 Boolclass 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 typeclassinstance 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

@FunctionalInterfaceinterface Function<A, B> { B apply(A a);}

Function<A, B> function1 = Functions::function;Function<A, B> function2 = a -> new B(a);

function :: a -> b

@FunctionalInterfaceinterface 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 -> bg :: b -> c

. :: (a -> b) -> (b -> c) -> a -> cf1 . f2 = \x -> f2 (f1 x)

h :: a -> ch = f . g

FunctorFunctorfor things that can be mapped over.

class Functor F where fmap :: (a -> b) -> F a -> F b

data Maybe a = Just a | Nothing

FunctorFunctorfor 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 ag :: 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)

CommonCommonimplementationsimplementations

Collection - container for a group ofvaluesOption/Maybe - for optional valuesEither - for results that either success orfailureFuture - for async computations

Option Option

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 TNone<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());

OptionalOptionalimport 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 monadfirst.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 avoidusege 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 RLeft<L, R> - container for values of type L that represents somefailure

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 functorsstream.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 monadsstream.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

FutureFutureJavaz 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)

CompletableFutureCompletableFutureImplementation from standard Java 8 library

final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 3 * 2);

// CompletableFuture is functorfuture.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 monadfuture.thenComposeAsync( i -> CompletableFuture.supplyAsync(() -> i * 2)); // CompletableFuture(12)

Why should I care?Why should I care?

Simple complexityComposabilityType safetyUnification