56
Javaz Javaz Functional design Functional design in Java 8 in Java 8

Thumbtack Expertise Days # 5 - Javaz

Embed Size (px)

Citation preview

Page 2: Thumbtack Expertise Days # 5 - Javaz

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

Page 3: Thumbtack Expertise Days # 5 - Javaz

Common functionalCommon functionalprogramming patternsprogramming patterns

FunctorApplicativeFunctorMonad

First appeared in Haskell programing langugage

Page 4: Thumbtack Expertise Days # 5 - Javaz

TypeclassesTypeclasses

First appeared in Haskell programing langugageIs a sort of interface that defines some behaviorYou can think of them kind of as Java interfaces

Page 5: Thumbtack Expertise Days # 5 - Javaz
Page 6: Thumbtack Expertise Days # 5 - Javaz

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

Page 7: Thumbtack Expertise Days # 5 - Javaz

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; }}

Page 8: Thumbtack Expertise Days # 5 - Javaz

FunctionFunction

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

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

Page 9: Thumbtack Expertise Days # 5 - Javaz

function :: a -> b

Page 10: Thumbtack Expertise Days # 5 - Javaz

@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);

Page 11: Thumbtack Expertise Days # 5 - Javaz

f :: a -> bg :: b -> c

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

h :: a -> ch = f . g

Page 12: Thumbtack Expertise Days # 5 - Javaz

FunctorFunctorfor things that can be mapped over.

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

Page 13: Thumbtack Expertise Days # 5 - Javaz
Page 14: Thumbtack Expertise Days # 5 - Javaz
Page 15: Thumbtack Expertise Days # 5 - Javaz
Page 16: Thumbtack Expertise Days # 5 - Javaz

data Maybe a = Just a | Nothing

Page 17: Thumbtack Expertise Days # 5 - Javaz
Page 18: Thumbtack Expertise Days # 5 - Javaz
Page 19: Thumbtack Expertise Days # 5 - Javaz
Page 20: Thumbtack Expertise Days # 5 - Javaz
Page 21: Thumbtack Expertise Days # 5 - Javaz
Page 22: Thumbtack Expertise Days # 5 - Javaz
Page 23: Thumbtack Expertise Days # 5 - Javaz

FunctorFunctorfor things that can be mapped over.

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

Page 24: Thumbtack Expertise Days # 5 - Javaz

Applicative FunctorApplicative Functor

class (Functor F) => Applicative F where pure :: a -> F a (<*>) :: F (a -> b) -> F a -> F b

Page 25: Thumbtack Expertise Days # 5 - Javaz
Page 26: Thumbtack Expertise Days # 5 - Javaz
Page 27: Thumbtack Expertise Days # 5 - Javaz
Page 28: Thumbtack Expertise Days # 5 - Javaz
Page 29: Thumbtack Expertise Days # 5 - Javaz

Applicative FunctorApplicative Functor

class (Functor F) => Applicative F where pure :: a -> F a (<*>) :: F (a -> b) -> F a -> F b

Page 30: Thumbtack Expertise Days # 5 - Javaz

MonadMonad

class Monad M where return :: a -> M a (>>=) :: M a -> (a -> M b) -> M b

Page 31: Thumbtack Expertise Days # 5 - Javaz
Page 32: Thumbtack Expertise Days # 5 - Javaz
Page 33: Thumbtack Expertise Days # 5 - Javaz
Page 34: Thumbtack Expertise Days # 5 - Javaz
Page 35: Thumbtack Expertise Days # 5 - Javaz
Page 36: Thumbtack Expertise Days # 5 - Javaz
Page 37: Thumbtack Expertise Days # 5 - Javaz

MonadMonad

class Monad M where return :: a -> M a (>>=) :: M a -> (a -> M b) -> M b

Page 38: Thumbtack Expertise Days # 5 - Javaz

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)

Page 39: Thumbtack Expertise Days # 5 - Javaz
Page 40: Thumbtack Expertise Days # 5 - Javaz

CommonCommonimplementationsimplementations

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

Page 41: Thumbtack Expertise Days # 5 - Javaz

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

Page 42: Thumbtack Expertise Days # 5 - Javaz

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));}

Page 43: Thumbtack Expertise Days # 5 - Javaz

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

Page 44: Thumbtack Expertise Days # 5 - Javaz

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

Page 45: Thumbtack Expertise Days # 5 - Javaz

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

Page 46: Thumbtack Expertise Days # 5 - Javaz

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)

Page 47: Thumbtack Expertise Days # 5 - Javaz

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

Page 48: Thumbtack Expertise Days # 5 - Javaz

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

Page 49: Thumbtack Expertise Days # 5 - Javaz

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

Page 50: Thumbtack Expertise Days # 5 - Javaz

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)

Page 51: Thumbtack Expertise Days # 5 - Javaz

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)

Page 52: Thumbtack Expertise Days # 5 - Javaz

Why should I care?Why should I care?

Simple complexityComposabilityType safetyUnification

Page 53: Thumbtack Expertise Days # 5 - Javaz

Какие практические достоинства инедостатки вы видете в

использовании функциональныхабстракций?

Page 54: Thumbtack Expertise Days # 5 - Javaz

Чем оператор связывания отличается отоператора композиции функций?

Page 55: Thumbtack Expertise Days # 5 - Javaz

Проанализируйте накладные расходыот реализации управления потоком

выполнения на основефункциональных паттернов по

сравнению с условными выражениямидля любого известного вам языка.

Page 56: Thumbtack Expertise Days # 5 - Javaz