Functional Libraries for Java

Functional Libraries for Java

DevoxxUK, London

363cf27411356afc37199a73bb58bcfe?s=128

Rabea Gransberger

May 10, 2018
Tweet

Transcript

  1. #FunctionalJava @rgransberger Functional Libraries for Java Rabea Gransberger @rgransberger https://rgra.github.io

  2. Libraries • jOOλ • VAVr • JUnit 5 • JDeferred

    • RxJava 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  3. Rabea Gransberger • Computer Science Diploma 2008 • Java Developer,

    Project Lead at MEKOS, Germany • Java Champion • Organization Team JUG Bremen, JCrete, JAlba 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) By Karte: NordNordWest, Lizenz: Creative Commons by-sa-3.0 de, CC BY-SA 3.0 de, https://commons.wikimedia.org/w/index.php?curid=35392837
  4. Back in 2013 @Devoxx UK • First public talk "Effective

    IDE Usage" 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  5. Functional Programming in Java https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7 10.05.2018 DevoxxUK / Functional Java

    (Rabea Gransberger @rgransberger)
  6. Functional Programming - Recap 10.05.2018 DevoxxUK / Functional Java (Rabea

    Gransberger @rgransberger)
  7. Functional Programming - Recap Functions and Values treated the same,

    pass functions around • Higher-Order Functions: Take function as param or return it • Referential transparency: call can be replaced by value • same input/same output • no side effects (exceptions) • Pure Functions: all functions called are referential transparent • Immutable data structures • Closures/Lambdas • Composition, Lifting, Currying • Filter / Map / Reduce 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  8. Pure Function List<String> values = Arrays.asList("A", "B", "C"); calculateResults(values); values

    => [A, B, C] 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  9. No Pure Function List<String> values = Arrays.asList("A", "B", "C"); calculateResults(values);

    static void calculateResults(List<String> values) { values.removeIf(s -> s.length() < 2); } => [ ] Favor Immutable data structures! 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  10. No Pure Function List<String> values = Arrays.asList("A", "B", "C"); calculateResults(values);

    static void calculateResults(List<String> values) { if(values.contains("A")){ throw new IllegalStateException("I hate A"); } } => IllegalStateException 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  11. Java 8 – Functional-"ish" Additions • SAM types enable Lambdas

    & are backwards compatible • New Functional Interfaces: Function, Predicate, Supplier, Consumer, .. • Default Methods now allow: list.sort( comparing(Person::getName) ) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  12. Java 8: Higher Order Function public static void main(String[] args)

    { System.out.println(add().applyAsInt(5, 6)); } private static IntBinaryOperator add() { return (a, b) -> a + b; } 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  13. Java 8 - Composition BiFunction<Integer, Integer, Integer> add = (x,

    y) -> x + y; BiFunction<…> addAndMultBy5 = add.andThen(x -> x * 5); addAndMultBy5.apply(2, 7); => 45 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  14. Java 8 - Composition / Currying System.out.println(curry(mult(), 5).apply(6)); IntBinaryOperator mult()

    { return (a, b) -> a * b; } IntFunction<Integer> curry(IntBinaryOperator op, int a){ return (b) -> op.applyAsInt(a, b); } 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  15. Java 8 – Streams: Filter / Map / Reduce intList.stream()

    .filter(i % 2 == 0) .forEach(System.out::println) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Terminal • reduce / collect / toArray • allMatch / anyMatch / noneMatch • count • findAny / findFirst • forEach / forEachOrdered / iterator / spliterator • max / min Intermediate • filter / distinct • map / flatMap • limit / skip • peek • sorted / unordered • dropWhile/takeWhile
  16. Functional Programming - Java ? Functions and Values treated the

    same, pass functions around √ Higher-Order Functions x Referential transparency x Pure Functions √ Closures/Lambdas √ Composition, Lifting, Currying √ Filter / Map / Reduce 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  17. Before we start… • Other JVM languages are more functional

    • Java is conservative • Additional API might be added later • As usual: Test drive a new library before you use it in production Performance?! 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  18. Birthday breakfast • Get list of employees • Find all

    birthdays this month • Group by birthday • Send E-Mail to each group and ask them to organize breakfast together Let’s code this! By Matt @ PEK from Taipei, Taiwan (Buffet brekafast) [CC BY-SA 2.0] via https://commons.wikimedia.org/wiki/File%3ABuffet_brekafast_(5078306699).jpg 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  19. By Anneli Salo (Own work) [CC BY-SA 3.0], https://commons.wikimedia.org/wiki/File%3AFolk_Music_%26_Limbo_Dance_C_IMG_2636.JPG 10.05.2018

    DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  20. jOOλ https://github.com/jOOQ/jOOL 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  21. jOOλ - useful extensions to Java 8 lambdas • Seq

    implements Stream, Iterable • sequential and ordered streams (parallel has no effect) • Similar functionality to StreamEx (no primitives) • SQL Like Collectors (RANK, MODE, BIT_AND) • Function1 - Function16 • Tuple1 - Tuple16 Seq.of(tuple(1, 2, 3, 4)) .mapToLong(t -> t.v1 * t.v2 * t.v3 * t.v4); 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  22. jOOλ DEMO 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  23. jOOλ – Window Functions window: Calculations across related elements, without

    grouping, with a single result per input element Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")), tuple("2016-09-11", new BigDecimal("-20"))) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Date Amount Balance 01.09.2016 0 11.09.2016 -20 € -20 20.09.2016 +100 € ? 27.09.2016 -5 € ?
  24. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  25. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) // ordering by date and taking into account // all previous of each date // until the element itself (0) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  26. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  27. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 2016-09-11 -> (2016-09-11, -20) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Window
  28. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 2016-09-11 -> (2016-09-11, -20) 2016-09-20 -> (2016-09-11, -20), (2016-09-20, 100) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Window
  29. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 2016-09-11 -> (2016-09-11, -20) 2016-09-20 -> (2016-09-11, -20), (2016-09-20, 100) 2016-09-27 -> (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Window
  30. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) .map(w -> w.value() // Tuple2 .concat( // Tuple2 -> Tuple3 // sum over all values in this window w.sum(t -> t.v2).orElse(BigDecimal.ZERO))) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  31. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) .map(w -> w.value().concat( // sum over all values in this window w.sum(t -> t.v2).orElse(BigDecimal.ZERO))) 2016-09-11 -> -20 2016-09-20 -> -20 + 100 = 80 2016-09-27 -> -20 + 100 - 5 = 75 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  32. jOOλ – Window Functions Seq.of(tuple("2016-09-27", new BigDecimal("-5")), tuple("2016-09-20", new BigDecimal("100")),

    tuple("2016-09-11", new BigDecimal("-20"))) .window(comparing(t -> t.v1), Long.MIN_VALUE, 0) .map(w -> w.value().concat( w.sum(t -> t.v2).orElse(BigDecimal.ZERO))) .printOut(); (2016-09-27, -5, 75) (2016-09-20, 100, 80) (2016-09-11, -20, -20) 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger) Date Amount Balance 01.09.2016 0 11.09.2016 -20 € -20 20.09.2016 +100 € 80 27.09.2016 -5 € 75
  33. VAVr http://www.vavr.io/ 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  34. VAVr - functional library for Java • Immutable & Persistent

    Collections: List, Set, Map in variations • Pure Functions • Tuple0 – 8 & Function0 – 8 • Enforces using Vavr data structures • Vavr -> Java: toJavaStream() • Java Stream -> Vavr: With Vavr Collectors • Stream-like methods on all Collections: but different concept 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  35. VAVr – Currying Function2<Integer, Integer, Integer> sum = (a, b)

    -> a + b; Function1<Integer, Integer> add2 = sum.curried().apply(2); add2.apply(4); => 6 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  36. VAVr – Lifting Partial Function: Only defined for non-zero divisors

    Function2<Integer,Integer,Integer> divide = (a, b) -> a / b; divide.apply(5, 0) => throws ArithmeticException Lift to total function: Defined for every input value Function2<Integer, Integer, Option<Integer>> safeDivide = Function2.lift(divide); safeDivide.apply(5, 0) => None 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  37. VAVr • Memoization: Function applied once, susequently returns same value

    Function0<Double> memo = of(Math::random) .memoized(); double first = memo.apply(); double second == memo.apply(); first == second 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  38. VAVr DEMO 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  39. JUnit 5 http://junit.org/junit5 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger

    @rgransberger)
  40. JUnit 5 – aka JUnit Lambda Expected Exceptions Throwable e

    = expectThrows(IOException.class,() -> { new URL("http://127.0.0.1") .openStream().read(); }); assertEquals("Connection refused: connect",e.getMessage()); 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  41. JUnit 5 - Dynamic tests Are all fibonacci numbers over

    2 odd? @Test void testFibonacci1() { testIsOdd(fibonacci(1)); } @Test void testFibonacci2(){ testIsOdd(fibonacci(2));} @Test void testFibonacci3(){ testIsOdd(fibonacci(3));} … @Test void testFibonacci20(){testIsOdd(fibonacci(20));} 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  42. JUnit 5 Demo 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger

    @rgransberger)
  43. Reactive CompletableFuture JDeferred RxJava 10.05.2018 DevoxxUK / Functional Java (Rabea

    Gransberger @rgransberger)
  44. Java 8 - CompletableFuture CompletableFuture<List<String>> future = readList(); future .thenApply(list

    -> "List read: " + list) .exceptionally(t -> "Failed: " + t.getMessage()) .thenAccept(System.out::println); 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  45. JDeferred http://jdeferred.org/ 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  46. JDeferred Java Deferred/Promise library similar to JQuery's Deferred Object. Deferred<>

    deferred = new DeferredObject<>(); deferred.promise() .done(result -> println("Completed: " + result)) .fail(rejection -> println("Rejected: " + rejection)) .progress(System.out::println) .always((state, result, rejection) -> println(".")); 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  47. RxJava 2 https://github.com/ReactiveX/RxJava 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger

    @rgransberger)
  48. RxJava - Reactive Extensions for the JVM • Excellent Javadoc

    with Flow Diagrams of operations 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  49. RxJava Demo 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  50. Pattern Matching Java x int eval(Node n) { switch(n) {

    case IntNode(int i): return i; case NegNode(Node n): return -eval(n); case AddNode(Node left, Node right): return eval(left) + eval(right); case MulNode(Node left, Node right): return eval(left) * eval(right); default: throw new IllegalStateException(n); }; } 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  51. Summary 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)

  52. Libraries • StreamEx • jOOλ • Stream Utils • Log4j

    2 • JUnit 5 • AssertJ • JDeferred • Eclipse Collections • VAVr • RxJava • Vert.x • Jinq 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)
  53. Q & A Slides & Code: https://rgra.github.io Video with Slides:

    https://www.youtube.com/watch?v=C5_2d2Bfg2Y Twitter: @rgransberger Feedback Welcome! 10.05.2018 DevoxxUK / Functional Java (Rabea Gransberger @rgransberger)