Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
FP in Java
               Project Lambda and beyond



by Mario Fusco
mario.fusco@gmail.com
twitter: @mariofusco
Project Lambda – A Brief History
•   2006 – Gosling: "We will never have closures in Java"
•   2007 – 3 different proposal...
From Single Method Interfaces …
public interface Comparator<T> {              Functional
    int compare(T o1, T o2);
}   ...
… To Lambda Expressions
Collections.sort(strings, (s1, s2) -> s1.compareToIgnoreCase(s2));


     Lambda expression are al...
Anatomy of a lambda expression
 A lambda expression is like a method: it provides a list of formal parameters and a body

...
Common JDK8 functional interfaces

Predicate     a property of the object passed as argument
Block      an action to be pe...
Why Lambdas?
API designers can build more powerful, expressive APIs
More room for generalization
  o Pass behaviors to a m...
An Example: Sorting
Comparator<Person> byAge = new Comparator<Person>() {
    public int compare(Person p1, Person p2) {
 ...
Can We Do Better?
Comparator<Person> byAge = Comparators.comparing(p -> p.getAge());


Comparator<Person> byAge = Comparat...
Extension methods
 interface Iterator<E> {
     boolean hasNext();
     E next();
     void remove();

      default void ...
Extension methods
    interface Iterator<E> {
        boolean hasNext();
        E next();
default void remove(); { throw ...
Internal VS External iteration
  for (Employee e : employees) {
      e.setSalary(e.getSalary() * 1.03);
  }
             ...
Streams - Efficiency with laziness
employees.stream()
         .filter(e -> e.getIncome() > 50000)
         .map(e -> e.ge...
Streams - Efficiency with laziness
           parallel()
employees.stream()
         .filter(e -> e.getIncome() > 50000)
 ...
So we have lambdas in Java …




   … now what?
The OOP/FP dualism - OOP
public class Bird { }

public class Cat {
    private Bird catch;
    private boolean full;

    ...
The OOP/FP dualism - FP
public class Bird { }

public class Cat {
    public CatWithCatch capture(Bird bird) { return new ...
Better Logging with Lambdas
if (log.isDebugEnabled()) {
    log.debug("The answer is " + answer);
}
                      ...
Side-effect isolation                     Reusability
class Player {
    String name;   public void declareWinner(Player p...
Side-effect isolation                     Reusability
class Player {
    String name;   public void declareWinner(Player p...
Side-effect isolation                     Reusability
class Player {
    String name;   public void declareWinner(Player p...
Using Streams
public boolean isPrimeImperative(int number) {
    if (number < 2) {
        return false;
    }
    for (in...
Working with infinite Streams
         take 25 (map (^2) [1..])




         (take 25 (squares-of (integers)))




       ...
Null references? No, Thanks
Errors source NPE is by far the most common exception in Java
Bloatware source Worsen readabil...
Options: the functional alternative
public abstract class Option<A> implements Iterable<A> {
    private Option() { }

   ...
Some
public static final class Some<A> extends Option<A> {
    private final A value;
    private Some(A value) { this.val...
None
public static final class None<A> extends Option<A> {

    public static final None NONE = new None();

    private N...
Example: if the value associated with a given key
    is a String representing a positive integer returns
      that integ...
Null vs. Option
int readPositiveIntParam(Map<String, String> params, String name) {
    String value = params.get(name);
 ...
Exceptions? Yes, but …
Often abused, especially for flow control
Checked Exceptions harm API extensibility/modificability
...
Exceptions? Yes, but …
Often abused, especially for flow control
Checked Exceptions harm API extensibility/modificability
...
Exceptions? Yes, but …
Often abused, especially for flow control
Checked Exceptions harm API extensibility/modificability
...
SalaryCalculator
public class SalaryCalculator {
    // B = basic + 20%
    public double plusAllowance(double d) { return...
Endomorphisms & Monoids
    interface Endomorphism<A> extends Function<A, A> { }


    interface Monoid<A> {
        A app...
FluentEndoMonoid
public class FluentEndoMonoid<A> implements EndoMonoid<A> {
    private final Endomorphism<A> endo;

    ...
Functional SalaryCalculator

public class SalaryCalculator {

    public double calculate(double basic, boolean... bs) {
 ...
The bottom line


Java is getting functional

 EMBRACE IT!
References
Thanks … Questions?




Q                                                 A
Mario Fusco                          mario.fus...
Upcoming SlideShare
Loading in …5
×

of

FP in Java - Project Lambda and beyond Slide 1 FP in Java - Project Lambda and beyond Slide 2 FP in Java - Project Lambda and beyond Slide 3 FP in Java - Project Lambda and beyond Slide 4 FP in Java - Project Lambda and beyond Slide 5 FP in Java - Project Lambda and beyond Slide 6 FP in Java - Project Lambda and beyond Slide 7 FP in Java - Project Lambda and beyond Slide 8 FP in Java - Project Lambda and beyond Slide 9 FP in Java - Project Lambda and beyond Slide 10 FP in Java - Project Lambda and beyond Slide 11 FP in Java - Project Lambda and beyond Slide 12 FP in Java - Project Lambda and beyond Slide 13 FP in Java - Project Lambda and beyond Slide 14 FP in Java - Project Lambda and beyond Slide 15 FP in Java - Project Lambda and beyond Slide 16 FP in Java - Project Lambda and beyond Slide 17 FP in Java - Project Lambda and beyond Slide 18 FP in Java - Project Lambda and beyond Slide 19 FP in Java - Project Lambda and beyond Slide 20 FP in Java - Project Lambda and beyond Slide 21 FP in Java - Project Lambda and beyond Slide 22 FP in Java - Project Lambda and beyond Slide 23 FP in Java - Project Lambda and beyond Slide 24 FP in Java - Project Lambda and beyond Slide 25 FP in Java - Project Lambda and beyond Slide 26 FP in Java - Project Lambda and beyond Slide 27 FP in Java - Project Lambda and beyond Slide 28 FP in Java - Project Lambda and beyond Slide 29 FP in Java - Project Lambda and beyond Slide 30 FP in Java - Project Lambda and beyond Slide 31 FP in Java - Project Lambda and beyond Slide 32 FP in Java - Project Lambda and beyond Slide 33 FP in Java - Project Lambda and beyond Slide 34 FP in Java - Project Lambda and beyond Slide 35 FP in Java - Project Lambda and beyond Slide 36 FP in Java - Project Lambda and beyond Slide 37 FP in Java - Project Lambda and beyond Slide 38 FP in Java - Project Lambda and beyond Slide 39
Upcoming SlideShare
Hammurabi
Next
Download to read offline and view in fullscreen.

22 Likes

Share

Download to read offline

FP in Java - Project Lambda and beyond

Download to read offline

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

FP in Java - Project Lambda and beyond

  1. FP in Java Project Lambda and beyond by Mario Fusco mario.fusco@gmail.com twitter: @mariofusco
  2. Project Lambda – A Brief History • 2006 – Gosling: "We will never have closures in Java" • 2007 – 3 different proposals for closures in Java • 2008 – Reinhold: "We will never have closures in Java" • 2009 – Start of project Lambda (JSR 335) public boolean javaWillHaveClosure() { return currentYear % 2 == 1; }
  3. From Single Method Interfaces … public interface Comparator<T> { Functional int compare(T o1, T o2); } Interface Collections.sort(strings, new Comparator<String>() { public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); } }); Bulky syntax Confusion surrounding the meaning of names and this Inability to capture non-final local variables Inability to abstract over control flow
  4. … To Lambda Expressions Collections.sort(strings, (s1, s2) -> s1.compareToIgnoreCase(s2)); Lambda expression are always converted to instance of a functional interface Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2); Compiler figures out the types No need of changing the JVM to create a new type for lambda expressions
  5. Anatomy of a lambda expression A lambda expression is like a method: it provides a list of formal parameters and a body The formal parameters of a lambda expression may have either inferred or s -> s.length() declared types (int x, int y) -> x + y () -> 42 Return is implicit and can be omitted (x, y, z) -> { if (x) { return y; A lambda body is either a } else { single expression or a block return z; } }
  6. Common JDK8 functional interfaces Predicate a property of the object passed as argument Block an action to be performed with the object passed as argument Function transform a T to a U BiFunction transform a (T, U) to a V Supplier provide an instance of a T (such as a factory) UnaryOperator a unary operator from T -> T BinaryOperator a binary operator from (T, T) -> T
  7. Why Lambdas? API designers can build more powerful, expressive APIs More room for generalization o Pass behaviors to a method together with normal data Libraries remain in control of computation o e.g. internal vs. external iteration More opportunities for optimization o Laziness o Parallelism o Out-of-order execution More regular and then more readable code o e.g. nested loops vs. pipelined (fluent) operations Better composability and reusability
  8. An Example: Sorting Comparator<Person> byAge = new Comparator<Person>() { public int compare(Person p1, Person p2) { return p1.getAge() – p2.getAge(); Functional interface } }; Lambda expression Collections.sort(people, byAge); Comparator<Person> byAge = (p1, p2) -> p1.getAge() – p2.getAge(); Collections.sort(people, (p1, p2) -> p1.getAge() – p2.getAge());
  9. Can We Do Better? Comparator<Person> byAge = Comparators.comparing(p -> p.getAge()); Comparator<Person> byAge = Comparators.comparing(Person::getAge); Method reference Readability Collections.sort(people, comparing(Person::getAge)); Reusability Collections.sort(people, comparing(Person::getAge).reverse()); Composability Collections.sort(people, comparing(Person::getAge) .compose(comparing(Person::getName)));
  10. Extension methods interface Iterator<E> { boolean hasNext(); E next(); void remove(); default void forEach(Block<? super E> block) { while (hasNext()) block.accept(next()); } } Add methods to existing interfaces without breaking the backward compatibility Primary goal is API evolution, but useful as an inheritance mechanism on its own Add multiple inheritance of behavior to the always existed multiple inheritance of type, but no multiple inheritance of state
  11. Extension methods interface Iterator<E> { boolean hasNext(); E next(); default void remove(); { throw new UnsupportedOperationException(); } remove() default void forEach(Block<? super E> block) { while (hasNext()) block.accept(next()); } } Add methods to existing interfaces without breaking the backward compatibility Primary goal is API evolution, but useful as an inheritance mechanism on its own Add multiple inheritance of behavior to the always existed multiple inheritance of type, but no multiple inheritance of state Can be used to declare “optional” methods
  12. Internal VS External iteration for (Employee e : employees) { e.setSalary(e.getSalary() * 1.03); } ̶ Inherently serial ̶ Client has to manage iteration ̶ Nested loops are poorly readable employees.forEach(e -> e.setSalary(e.getSalary() * 1.03)); Not only a syntactic change! + Library is in control opportunity for internal optimizations as parallelization, lazy evaluation, out-of-order execution + More what, less how better readability + Fluent (pipelined) operations better readability + Client can pass behaviors into the API as data possibility to abstract and generalize over behavior more powerful, expressive APIs
  13. Streams - Efficiency with laziness employees.stream() .filter(e -> e.getIncome() > 50000) .map(e -> e.getName()) .forEach(System.out::println); Represents a stream of values Not a data structure: doesn't store values Source can be Collection, array, generating function, I/O .... Encourages a pipelined ( "fluent" ) usage style Operations are divided between intermediate and terminal Lazy in nature: only terminal operations actually trigger a computation
  14. Streams - Efficiency with laziness parallel() employees.stream() .filter(e -> e.getIncome() > 50000) .map(e -> e.getName()) .forEach(System.out::println); Represents a stream of values Not a data structure: doesn't store values Source can be Collection, array, generating function, I/O .... Encourages a pipelined ( "fluent" ) usage style Operations are divided between intermediate and terminal Lazy in nature: only terminal operations actually trigger a computation Also available a parallel stream (using the Fork/Join framework)
  15. So we have lambdas in Java … … now what?
  16. The OOP/FP dualism - OOP public class Bird { } public class Cat { private Bird catch; private boolean full; public void capture(Bird bird) { catch = bird; The story } public void eat() { full = true; catch = null; } } Cat cat = new Cat(); Bird bird = new Bird(); cat.capture(bird); cat.eat();
  17. The OOP/FP dualism - FP public class Bird { } public class Cat { public CatWithCatch capture(Bird bird) { return new CatWithCatch(bird); } } public class CatWithCatch { Immutability private final Bird catch; public CatWithCatch(Bird bird) { catch = bird; } public FullCat eat() { return new FullCat(); } Emphasis on verbs } instead of names public class FullCat { } BiFunction<Cat, Bird, FullCat> story = ((BiFunction<Cat, Bird, CatWithCatch>)Cat::capture) .compose(CatWithCatch::eat); FullCat fullCat = story.apply( new Cat(), new Bird() ); No need to test internal state: correctness enforced by the compiler
  18. Better Logging with Lambdas if (log.isDebugEnabled()) { log.debug("The answer is " + answer); } Invokes answer.toString() and does the Strings concatenation even when not necessary Can we delay the String creation and execute it only when strictly necessary without (explicitly) using an if? log.debug(()-> "The answer is " + answer); public void debug(Callable<String> lambda) { if (isDebugEnabled()) { debug(lambda.call()); } }
  19. Side-effect isolation Reusability class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); }
  20. Side-effect isolation Reusability class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); } Separate computational logic public Player maxScore(Player p1, Player p2) { from side effects return p1.score > p2.score ? p1 : p2; } public void winner(Player p1, Player p2) { declareWinner(maxScore(p1, p2)); }
  21. Side-effect isolation Reusability class Player { String name; public void declareWinner(Player p) { int score; System.out.println(p.name + " wins!"); } } public void winner(Player p1, Player p2) { if (p1.score > p2.score) declareWinner(p1) else declareWinner(p2); } Separate computational logic public Player maxScore(Player p1, Player p2) { from side effects return p1.score > p2.score ? p1 : p2; } public void winner(Player p1, Player p2) { declareWinner(maxScore(p1, p2)); } declareWinner(players.stream().reduce(this::maxScore).get()) reuse maxScore as a BinaryOperator to compute the winner among a list of players
  22. Using Streams public boolean isPrimeImperative(int number) { if (number < 2) { return false; } for (int i = 2; i < (int) Math.sqrt(number) + 1; i++) { if ( number % i == 0 ) { return false; } } return true; } public boolean isPrimeFunctional(int number) { return number > 1 && Streams.intRange(2, (int) Math.sqrt(number) + 1) .noneMatch(divisor -> number % divisor == 0); }
  23. Working with infinite Streams take 25 (map (^2) [1..]) (take 25 (squares-of (integers))) Stream.from(1).map(_ ^ 2).take(25).toArray Stream<Integer> integers = Streams.iterate(1, i -> i + 1); int[] result = integers.map(i -> i ^ 2).limit(25).toArray();
  24. Null references? No, Thanks Errors source NPE is by far the most common exception in Java Bloatware source Worsen readability by making necessary to fill our code with null checks Meaningless Don't have any semantic meaning and in particular are the wrong way to model the absence of a value in a statically typed language Breaks Java philosophy Java always hides pointers to developers, except in one case: the null pointer A hole in the type system Null has the bottom type, meaning that it can be assigned to any reference type: this is a problem because, when propagated to another part of the system, you have no idea what that null was initially supposed to be Tony Hoare, who invented the null reference in 1965 while working on an object oriented language called ALGOL W, called its invention his “billion dollar mistake”
  25. Options: the functional alternative public abstract class Option<A> implements Iterable<A> { private Option() { } public abstract <B> Option<B> map(Function<A, B> mapper); public abstract <B> Option<B> flatMap(Function<A, Option<B>> mapper); public abstract Option<A> filter(Predicate<A> predicate); public abstract A getOrElse(A def); public abstract boolean isDefined(); public static <A> Some<A> some(A value) { if (value == null) throw new NullPointerException(); return new Some<A>(value); } public static <A> None<A> none() { return None.NONE; } public static <A> Option<A> option(A value) { return value == null ? none() : some(value); } public static final class None<A> extends Option<A> { ... } public static final class Some<A> extends Option<A> { ... } }
  26. Some public static final class Some<A> extends Option<A> { private final A value; private Some(A value) { this.value = value; } public <B> Option<B> map(Function<A, B> mapper) { return some( mapper.apply(value) ); } public <B> Option<B> flatMap(Function<A, Option<B>> mapper) { return (Option<B>) mapper.apply(value); } public Option<A> filter(Predicate<? super A> predicate) { return predicate.test(value)) ? this : None.NONE; } public A getOrElse(A def) { return value; } public boolean isDefined() { return false; } }
  27. None public static final class None<A> extends Option<A> { public static final None NONE = new None(); private None() { } public <B> Option<B> map(Function<A, B> mapper) { return NONE; } public <B> Option<B> flatMap(Function<A, Option<B>> mapper) { return NONE; } public Option<A> filter(Predicate<A> predicate) { return NONE; } public A getOrElse(A def) { return def; } public boolean isDefined() { return false; } }
  28. Example: if the value associated with a given key is a String representing a positive integer returns that integer, but returns zero in all other case @Test public void testReturnPositiveIntegersOrZero() { Map<String, String> param = new HashMap<String, String>(); param.put("a", "5"); param.put("b", "true"); param.put("c", "-3"); // the value of the key "a" is a String representing a // positive int so return it assertEquals(5, readPositiveIntParam(param, "a")); // returns zero since the value of the key "b" is not an int assertEquals(0, readPositiveIntParam(param, "b")); // returns zero since the value of the key "c" is a negative int assertEquals(0, readPositiveIntParam(param, "c")); // returns zero since there is no key "d" in the map assertEquals(0, readPositiveIntParam(param, "d")); }
  29. Null vs. Option int readPositiveIntParam(Map<String, String> params, String name) { String value = params.get(name); if (value == null) return 0; int i = 0; try { i = Integer.parseInt(value); } catch (NumberFormatException e) { } return i < 0 ? 0 : i; } int readPositiveIntParam(Map<String, String> params, String name) { return asOption(params.get(name)) .flatMap(s -> { try { return some(Integer.parseInt(s)); } catch (NumberFormatException e) { return none(); } }) .filter(i -> i > 0) .getOrElse(0); }
  30. Exceptions? Yes, but … Often abused, especially for flow control Checked Exceptions harm API extensibility/modificability Not composable: in presence of multiple errors only the first one is reported In the end just a GLORIFIED MULTILEVEL GOTO
  31. Exceptions? Yes, but … Often abused, especially for flow control Checked Exceptions harm API extensibility/modificability Not composable: in presence of multiple errors only the first one is reported In the end just a GLORIFIED MULTILEVEL GOTO Either/Validation: the functional alternative The functional way of returning a value which can actually be one of two values: the error/exception (Left) or the correct value (Right) Validation<Exception, Value>
  32. Exceptions? Yes, but … Often abused, especially for flow control Checked Exceptions harm API extensibility/modificability Not composable: in presence of multiple errors only the first one is reported In the end just a GLORIFIED MULTILEVEL GOTO Either/Validation: the functional alternative The functional way of returning a value which can actually be one of two values: the error/exception (Left) or the correct value (Right) Composable: can accumulate multiple errors Validation<List<Exception>, Value> Validation<Exception, Value>
  33. SalaryCalculator public class SalaryCalculator { // B = basic + 20% public double plusAllowance(double d) { return d * 1.2; } // C = B + 10% public double plusBonus(double d) { return d * 1.1; } // D = C - 30% public double plusTax(double d) { return d * 0.7; } // E = D - 10% public double plusSurcharge(double d) { return d * 0.9; } public double calculate(double basic, boolean... bs) { double salary = basic; if (bs[0]) salary = plusAllowance(salary); if (bs[1]) salary = plusBonus(salary); if (bs[2]) salary = plusTax(salary); if (bs[3]) salary = plusSurcharge(salary); return salary; } }
  34. Endomorphisms & Monoids interface Endomorphism<A> extends Function<A, A> { } interface Monoid<A> { A append(A a1, A a2); A zero(); } interface EndoMonoid<A> extends Monoid<Endomorphism<A>> { @Override default Endomorphism<A> append(Endomorphism<A> a1, Endomorphism<A> a2) { return (A a) -> a2.apply(a1.apply(a)); } @Override default Endomorphism<A> zero() { return a -> a; } }
  35. FluentEndoMonoid public class FluentEndoMonoid<A> implements EndoMonoid<A> { private final Endomorphism<A> endo; public FluentEndoMonoid(Endomorphism<A> endo) { this.endo = endo; } public FluentEndoMonoid(Endomorphism<A> endo, boolean b) { this.endo = b ? endo : zero(); } public FluentEndoMonoid<A> add(Endomorphism<A> other) { return new FluentEndoMonoid<A>(append(endo, other)); } public FluentEndoMonoid<A> add(Endomorphism<A> other, boolean b) { return add(b ? other : zero()); } public Endomorphism<A> get() { return endo; } public static <A> FluentEndoMonoid<A> endo(Endomorphism<A> f, boolean b) { return new FluentEndoMonoid<A>(f, b); } }
  36. Functional SalaryCalculator public class SalaryCalculator { public double calculate(double basic, boolean... bs) { return endo((Endomorphism<Double>) this::plusAllowance, bs[0]) .add(this::plusBonus, bs[1]) .add(this::plusTax, bs[2]) .add(this::plusSurcharge, bs[3]) .get() .apply(basic); } }
  37. The bottom line Java is getting functional EMBRACE IT!
  38. References
  39. Thanks … Questions? Q A Mario Fusco mario.fusco@gmail.com Red Hat – Senior Software Engineer twitter: @mariofusco
  • MdMizanurRahaman19

    Apr. 11, 2021
  • ssuserb8ce5e1

    Jun. 11, 2019
  • KetanPatel219

    May. 1, 2018
  • ffch1996

    Dec. 2, 2017
  • partha_net123

    Mar. 2, 2017
  • BeatSchumacher2

    Jan. 12, 2017
  • shubhammamde1

    Jan. 19, 2016
  • LaurentCouturier

    Nov. 13, 2015
  • dohyoonkim7

    Jul. 16, 2015
  • nicolaferraro

    Mar. 28, 2015
  • javaonkar

    Mar. 9, 2015
  • whzdf

    Feb. 17, 2015
  • stitakis

    Jun. 18, 2013
  • carlo.bonamico

    Apr. 9, 2013
  • itzsaratechie

    Mar. 28, 2013
  • fabrizioamadei

    Mar. 25, 2013
  • PTomeo1

    Mar. 24, 2013
  • mox601

    Mar. 20, 2013
  • PetroRudenko

    Mar. 14, 2013
  • celialiborio1

    Mar. 14, 2013

Views

Total views

19,357

On Slideshare

0

From embeds

0

Number of embeds

321

Actions

Downloads

158

Shares

0

Comments

0

Likes

22

×