Upload
dubs-vadim
View
101
Download
0
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);
@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
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
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)