Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Functional Libraries for Java 8+ (Oredev)

Functional Libraries for Java 8+ (Oredev)

Oredev, Malmö, Sweden

Rabea Gransberger

November 08, 2017
Tweet

More Decks by Rabea Gransberger

Other Decks in Programming

Transcript

  1. Libraries • jOOλ • VAVR • JUnit 5 • JDeferred

    • RxJava • Vert.x 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  2. Rabea Gransberger • Computer Science Diploma 2008 • Java Developer,

    Project Lead at MEKOS, Germany • Organization Team JUG Bremen, JCrete 08.11.2017 Øredev / 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
  3. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  4. Pure Function List<String> values = Arrays.asList("A", "B", "C"); calculateResults(values); values

    => [A, B, C] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  5. 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! 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  6. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  7. 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) ) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  8. 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; } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  9. Java 8 - Composition BiFunction<Integer, Integer, Integer> add = (x,

    y) -> x + y; BiFunction<…> addAndMultBy5 = add.andThen(x -> x * 5); addAndMultBy5.apply(2, 7); => 45 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  10. 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); } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  11. Java 8 – Streams: Filter / Map / Reduce intList.stream()

    .filter(i % 2 == 0) .forEach(System.out::println) 08.11.2017 Øredev / 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
  12. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  13. 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?! 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  14. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  15. Java 8 Example Map<MonthDay, List<Employee>> byDate = persons.stream() .filter(p ->

    p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); byDate.entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  16. Java 8 • How's that method called again? • Comparator

    instead of Function • Functions like zip • How do I get a stream of lines from File? • Lack of Immutable data structures 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  17. StreamEx - Enhancing Java 8 Streams • StreamEx class wraps

    Stream • StreamEx.of(list.stream()) • StreamEx.of(1,2,3) • Allows parallel execution • Short-Cut Collectors: • stream.joining(",") instead of • stream.collect(joining(",")) • Additional Collectors in MoreCollectors and Joining (for Strings) • Special Streams/Collectors for primitives 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  18. public static void main(String[] args) { StreamEx<Employee> stream = of(getPersons(toList()));

    println(stream); printEMail(stream); } static void printEMail(Iterable<Employee> iterable) { for (Employee element : iterable) System.out.println(element.getEmail()); } static <T> void println(Stream<T> stream) { stream.forEach(System.out::println); } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  19. StreamEx – Factory Methods • StreamEx.ofLines(Path) • ofKeys/Values(Map) • cartesianProduct:

    [[A,B][1,2]] => [[A, 1], [A,2], [B, 1], [B, 2]] • split("Firstname-Name-Title", "-") => ["Firstname", "Name", "Title"] • zip: [[A,B,Rabea][1,2,Gransberger]] => [A1, B2, Rabea Gransberger] • ofTree(T, Function<T, Stream<T>>) StreamEx.ofTree(Paths.get("D:/"), listDirs()) => ["D:/", "D:/workspaces", "D:/workspaces/Devoxx"] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  20. StreamEx – EntryStream for Map.Entry • Factory methods: EntryStream.of(map) •

    Key/Value pairs: of("Rabea","Gransberger","Devoxx, "MA") => [Rabea ~ Gransberger, Devoxx ~ MA] • Two Lists: [A,B][1,2] => [A ~ 1, B ~ 2] • map/filter/peek/remove separate for Keys/Values of(K,V,K2,V2).filterKeys(k -> k.endsWith("2")) => [K2 ~ V2] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  21. StreamEx – Cherry Picks • prepend/append: of(1,2).prepend(0) => [0,1,2] •

    foldLeft/foldRight: Aggregate into single result, starting left or right of(1,2,3).foldLeft(0, Integer::sum) => 6 • groupRuns(BiPredicate): groups adjacent elements of(A,B,A,A,B).groupRuns((x,y)->x.equals(y)) => [(A),(B),(A,A),(B)] • distinct(atLeast) distinct values which are contained atLeast times of(A,B,A,A,B,C).distinct(2) => [A,B] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  22. Java 8 Example Map<MonthDay, List<Employee>> byDate = persons.stream() .filter(p ->

    p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); byDate.entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  23. StreamEx - Enhancing Java 8 Streams Map<MonthDay, List<Employee>> byDate =

    StreamEx.of(persons) .filter(p -> p.getBirthday().getMonth() == currentMonth) .groupingBy(e -> MonthDay.from(e.getBirthday())); EntryStream.of(byDate) .filterValues(l -> l.size() > 1) .sortedBy(Map.Entry::getKey) .forKeyValue(List2Map::sendMail); Map<MonthDay, List<Employee>> byDate = persons.stream() .filter(p -> p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); byDate.entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  24. StreamEx - Enhancing Java 8 Streams StreamEx.of(persons) .filter(p -> p.getBirthday().getMonth()

    == currentMonth) .sortedBy(p -> MonthDay.from(p.getBirthday())) .groupRuns((p, n) -> from(p.getBirthday()) //StreamEx<List> .equals(from(n.getBirthday()))) .filter(list -> list.size() > 1) .forEach(this::sendMail); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  25. 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); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  26. jOOλ – Factory methods • Seq.cast(Stream, Class): cast all elements

    to class • cycle: repeat stream infinitly or certain amount of times • scanLeft/scanRight: fold with intermediate results • grouped: by Function resulting in Seq<Tuple2> • range(from,to[,step]): for byte, char, int, long, short, Instant • unfold(seed, Function) • zip/zipAll: with up to 16 Collections/Stream to Tuples/Streams 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  27. jOOλ – Helpers for single results • foldLeft/foldRight(stream, seed,BiFunction) producing

    folded result • groupBy(Function[,Function]): Resulting in a map • splitAt(postion): splitting stream at a position into 2 Streams • toCollection/toList/toMap/toSet • toString(String delimiter): Short for Joining • unzip: unzip one Stream into two with mapping functions 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  28. jOOλ - Unchecked Checked Exceptions not allowed in java.util.function Interfaces

    Seq.of(Paths.get("D:","test.csv")) .flatMap(file -> Files.lines(file)) .printOut(); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) throws IOException
  29. jOOλ - Unchecked Seq.of(Paths.get("D:","test.csv")) .flatMap(file -> { try {return Files.lines(file);}

    catch (IOException e) { throw new RuntimeException(e);} }) .printOut(); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  30. jOOλ - Unchecked Wraps Checked Exceptions into unchecked • Runnable

    • Comparator • Consumer/BiConsumer • Function/BiFunction • Predicate/BiPredicate • Supplier • BinaryOperator / UnaryOperator • With Variants for primitives ToDoubleBiFunction etc. 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) Seq.of(Paths.get("D:","test.csv")) .flatMap(Unchecked.function(Files::lines)) .printOut();
  31. jOOλ – Cherry Picking • format: Format contents of stream

    (for debugging) • intersperse: Insert element between existing [a, b, c], 0 => [a,0,b,0,c] • leftOuterJoin: Take all from left, join with each right, by join criteria [a, b, c][1, 2] => [(a,1),(a,2),(b,1),(b,2),(c,null)] • rightOuterJoin: Take all from right, join with each left, by join criteria [a, b][1, 2, 3] => [(a,1),(b,1),(a,2),(b,2),(null,3)] • innerJoin: join until one of the Seq ends, by join criteria [a, b][1, 2, 3] => [(a,1),(b,1),(a,2),(b,2)] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  32. jOOλ – SQL Like Collectors (Agg) With optional Function, Comparator,

    Predicate • count / sum / avg / median • min / max • allMatch / anyMatch / noneMatch • bitAnd / bitOr • mode / modeAll • rank / denseRank / percentRank / percentile • commonPrefix / commonSuffix of Strings 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  33. Java 8 Example Map<MonthDay, List<Employee>> byDate = persons.stream() .filter(p ->

    p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); byDate.entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  34. jOOλ - useful extensions to Java 8 lambdas Seq.seq(persons) .filter(p

    -> p.getBirthday().getMonth() == currentMonth) // Seq<Tuple2<MonthDay,List<Employee>>> .grouped(e -> MonthDay.from(e.getBirthday()), toList()) .filter(t -> t.v2.size() > 1) .sorted(t -> t.v1) // Function .forEach(t -> sendMail(t.v1, t.v2)); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  35. 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"))) 08.11.2017 Øredev / 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 € ?
  36. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  37. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  38. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  39. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) Window
  40. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) Window
  41. 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) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) Window
  42. 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))) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  43. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  44. 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) 08.11.2017 Øredev / 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
  45. Stream Utils • Cycling: Takes a stream and repeats it

    forever StreamUtils.cycling(list.stream()).limit(1000) • Grouping: [a, b, c, d] => [[a, b], [c, d]] • Repeating: [a, b, c, d] => [a, a, b, b, c, c, d, d] • Rolling: [a, b, c, d, e] => [[a, b], [b, c], [c, d] , [d, e]] • Zipping: The zipping operator takes two streams and a BiFunction [a,b][1,2] => [a1, b2] • Interrupting/Gating: Stops/Starts stream processing by predicate [a,b,c,d] Interrupt c => [a, b] Gate c => [c, d] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  46. Stream Utils - Example Election Time, let‘s count the votes

    08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) interface Vote { default int getCandiate1() {return 0;} default int getCandidate2() {return 0;} default int getInvalid() {return 0;} } class VotingCard { //valid //invalid String candidate1Vote; //x //x String candidate2Vote; //null //Hate U }
  47. Stream Utils - Example List<VotingCard> votes = ….. int invalidVotes

    = StreamUtils.validate(votes.stream(), Elections::validate, //VotingCard -> boolean Elections::validVote, //VotingCard -> (Valid)Vote Elections::invalidVote)//VotingCard -> (Invalid)Vote .mapToInt(Vote::getInvalid) .sum(); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger) interface Vote { default int getCandiate1() {return 0;} default int getCandidate2() {return 0;} default int getInvalid() {return 0;} } class VotingCard { //valid //invalid String candidate1Vote; //x //x String candidate2Vote; //null //Hate U }
  48. Stream Utils • Traversing: Takes a set of streams and

    builds a stream of substreams stream0 = ["a00", "a01", "a02"] stream1 = ["a10", "a11", "a12"] stream2 = ["a20", "a21", "a22"] [["a00", "a10", "a20"], ["a01", "a11", "a21"], ["a02", "a12", "a22"]] • Weaving: Traversing with flatMapping ["a00", "a10", "a20", "a01", "a11", "a21", "a02", "a12", "a22"] 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  49. Log4j 2.x Java 8 lambda support for lazy logging //<

    Java 8 if (logger.isTraceEnabled()) { logger.trace("Long-running: {}", expensiveOperation()); } //>= Java 8 logger.trace("Long-running: {}", () -> expensiveOperation()); logger.info( () -> "Long-running operation:" + expensiveOperation()); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  50. Eclipse Collections - Features you want with the collections you

    need • Mutable, Immutable and primitive Collections • List, Set, Bag, Stack, Map, MultiMap, BiMap • MutableList<String> mutable = Lists.mutable.of("A", "B"); • ImutableIntList intList = IntLists.immutable.of(1, 2, 3); • Implements Java Collection interfaces and thus provide Stream • Collections have methods directly without Stream • More Collectors in Class Collectors2 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  51. Eclipse Collections - Basics • Different naming: detect vs. findFirst,

    select vs. filter • Does not return Optional but null if nothing found Person person = people .selectWith(Person::hasPet, PetType.CAT) .detect(p -> p.getFirstName().startsWith("R")); Intermediate operations return new lists 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  52. Eclipse Collections - Primitives MutableIntList numberOfPets = this.people .sortThisByInt(p ->

    p.getNumberOfPets()) .collectInt(p -> p.getNumberOfPets()); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  53. VAVR - functional library for Java 8 • 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  54. VAVR – Currying Function2<Integer, Integer, Integer> sum = (a, b)

    -> a + b; Function1<Integer, Integer> add2 = sum.curried().apply(2); add2.apply(4); => 6 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  55. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  56. 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 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  57. VAVR • Either: Either the left or right value Either<String,Integer>

    • Validation: Helper for chains of data validation and object creation Validation.combine(validName(name), validAge(age)) .ap(Person::new) 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  58. Java 8 Example Map<MonthDay, List<Employee>> byDate = persons.stream() .filter(p ->

    p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); byDate.entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  59. VAVR - Example io.vavr.collection.List<Employee> persons = … persons.filter(p -> p.getBirthday().getMonth()

    == currentMonth) .groupBy(e -> MonthDay.from(e.getBirthday())) .filter(v -> v._2.size() > 1) .forEach(VavrTest::sendMail); persons.stream() .filter(p -> p.getBirthday().getMonth() == currentMonth) .collect(groupingBy(e -> MonthDay.from(e.getBirthday()))); .entrySet().stream() .filter(e -> e.getValue().size() > 1) .sorted(comparing(Map.Entry::getKey)) .forEach(e -> sendMail(e.getKey(), e.getValue())); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  60. VAVR - Matching String s = Match(i).of( Case(is(1), "one"), Case(is(2),

    "two"), Case($(), "?") ); 1 => one 2 => two 3 => ? 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  61. VAVR – Matching with side-effects Match(arg).of( Case(isIn("-h", "--help"), o ->

    run(this::displayHelp)), Case(isIn("-v", "--version"), o -> run(this::displayVersion)), Case($(), o -> run(() -> { throw new IllegalArgumentException(arg); })) ); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  62. JUnit 5 • Beta in Milestone 2, GA expected end

    of 2016 • @Test @DisplayName("My 1st JUnit 5 test!") void myFirstTest() {} • @Tag("fast") void testIsFastEnoughForHourlyRuns() {} • Parameter Injection: void myFirstTest(TestInfo info) { info.getDisplayName(); } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)  not public  Meta-Annotations possible, @MyFastTag
  63. JUnit 5 – aka JUnit Lambda Lazy message evaluation: org.junit.jupiter.api.Assertions

    assertEquals(2, 2); assertEquals(4, 4, "optional message as last parameter."); assertTrue(2 == 2, () -> "messages can be lazily evaluated"); assumeTrue("DEV".equals(System.getenv("ENV")), () -> "Aborting test: not on dev workstation"); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  64. JUnit 5 – aka JUnit Lambda Grouped Asserts: assertAll("names", ()

    -> assertEquals("John", firstname), () -> assertEquals("User", lastname)); => org.opentest4j.MultipleFailuresError: names (2 failures) expected: <John> but was: <Rabea> expected: <User> but was: <Gransberger> 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  65. 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()); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  66. 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));} 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  67. JUnit 5 - Dynamic tests return IntStream.rangeClosed(1, 20) .map(this::fibonacci) 08.11.2017

    Øredev / Functional Java (Rabea Gransberger @rgransberger)
  68. JUnit 5 - Dynamic tests return IntStream.rangeClosed(1, 20) .map(this::fibonacci) .mapToObj(fibo

    -> dynamicTest( "Fibonacci = " + fibo, // Name () -> testIsOdd(fibo))); // Test Body } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  69. JUnit 5 - Dynamic tests @TestFactory @DisplayName("all Fibonacci numbers are

    odd") Stream<DynamicTest> testFactory() { return IntStream.rangeClosed(1, 20) .map(this::fibonacci) .mapToObj(fibo -> dynamicTest( "Fibonacci = " + fibo, // Name () -> testIsOdd(fibo))); // Test Body } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  70. JUnit 5 - Dynamic tests @TestFactory @DisplayName("all Fibonacci numbers are

    odd") Stream<DynamicTest> testFactory() { return IntStream.range(1, 20) .map(this::fibonacci) .mapToObj(fibo -> dynamicTest("Fibonacci = " + fibo, () -> testIsOdd(fibo))); // Test Body } 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  71. AssertJ – Fluent Assertions assertThat(fellowshipOfTheRing) .filteredOn(character -> character.getName().contains("o")) .containsOnly(aragorn, frodo,

    legolas, boromir) .extracting(character -> character.getRace().getName()) .contains("Hobbit", "Elf", "Man"); assertThat(contentOf(xFile)) .startsWith("The Truth") .contains("Is Out") .endsWith("There"); assertThat(frodo) .isEqualToComparingFieldByField(frodoClone); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  72. AssertJ – Fluent Assertions assertThat(myName) .startsWith("Fro") .endsWith("do") .isEqualToIgnoringCase("frodo"); java.lang.AssertionError: Expecting:

    <"Rabea"> to start with: <"Fro"> 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  73. Jinq - LINQ for Java SQL: SELECT * FROM Customer

    C WHERE C.Name = 'Alice' Proof of concept: database .customerStream() .where(c -> c.getName().equals("Alice")); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  74. Java 8 - CompletableFuture CompletableFuture<List<String>> future = readList(); future .thenApply(list

    -> "List read: " + list) .exceptionally(t -> "Failed: " + t.getMessage()) .thenAccept(System.out::println); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  75. 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(".")); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  76. RxJava - Reactive Extensions for the JVM • Works on

    Java 6+ with Functional Interfaces for Java 8 • Observable & Flowable are the base classes Observable.fromIterable(asList("Rabea", "Devoxx")) .subscribe(System.out::println); • Sources: InputStreams, Database, Message Bus etc 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  77. RxJava - Reactive Extensions for the JVM • Excellent Javadoc

    with Flow Diagrams of operations 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  78. RxJava - Subscribe Observable<String> observ = just("Rabea", "Devoxx", "RxJava") .filter(s

    -> s.startsWith("R")); observ .map(s -> s.length()) .subscribe(System.out::println); => 5, 6 observ .subscribe(System.out::println); => Rabea, RxJava 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  79. RxJava - Basics • map/flatMap/cast/scan • filter • reduce/count /

    first/last • forEach • distinct/limit/skip • zip/merge/concat/repeat(cycle) • startWith(prepend) / endWith (append) • toList/toMap/toCollection 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  80. RxJava – Time is ticking • interval: Observable which creates

    numbers in time intervals • onBackpressureDrop: Drop items when backpressure builds up • sample: Sampling items in time intervals • take/takeLast/skip/skipLast:Take/Skip items at start/end time window • timeout: apply timeout for each emitted item • window: Group items in time windows 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  81. RxJava – Time is ticking • delaySubscription (delay, TimeUnit) •

    interval: Observable which creates numbers in time intervals • onBackpressureDrop: Drop items when backpressure builds up • sample: Sampling items in time intervals • take/takeLast/skip/skipLast:Take/Skip items at start/end time window • throttleFirst/Last/withTimeout: Get items in a time window • timeout: apply timeout for each emitted item • window: Group items in time windows 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  82. RxJava – Errors under control • onErrorResumeNext: Resume with another

    Observable • retry: Retry to subscribe if error occurs • doOnError: Invoke action on error • …DelayError like concatDelayError, delays exception until terminated 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  83. Java 9 Flow API The Flow APIs in JDK 9

    correspond to the Reactive Streams Specification, which is a defacto standard • Flow.Publisher<T>: subscribe • Flow.Subscriber<T>: onSubscribe, onNext, onError, onComplete • Flow.Subscription: request, cancel • Flow.Processor<T,R> extends Flow.Subscriber<T>, Flow.Publisher<R> RxJava, Akka and others will likely imlement Flow in the future 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  84. Vert.x – reactive applications on the JVM Vert.x is event

    driven and non blocking Has different components, use only what you need: • Core & Web • Data Access: MongoDB, JDBC, Redis, SQL • Integration: Mail Client, Camel Bridge • Authentication: JWT, Shiro, OAuth2 • Reactive: RxJava, Reactive Streams • Microservices: Circuit Breaker, Kubernetes, Consul • Devops: Dropwizard Metrics, Docker • Clustering: Hazelcast, JGroups, Apache Ignite 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  85. Vert.x – Simple HTTP Server Vertx.vertx() .createHttpServer() .requestHandler(req -> req.response()

    .end("Hello World!")) .listen(8080, handler -> { if (handler.succeeded()) System.out.println("http://localhost:8080/"); else System.err.println("Failed to listen on 8080"); }); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  86. Vert.x – Read File vertx .fileSystem() .readFile("d:/test.csv", result -> {

    if (result.succeeded()) System.out.println(result.result()); else System.err.println(result.cause()); }); 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  87. Libraries • StreamEx • jOOλ • Stream Utils • Log4j

    2 • JUnit 5 • AssertJ • JDeferred • Eclipse Collections • VAVR • RxJava • Vert.x • Jinq 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  88. More Libraries • Java Functions: @FunctionalInterfaces for every function of

    0 to 3 arguments • Paguro: Type-safe versions of Clojure's immutable collections • Cucumber Java 8 Support: Step definitions with Lambdas • Ratpack: is a set of Java libraries for building modern HTTP applications. • Atlassian Fugue: Functional Extensions • Lagom: Build greenfield microservices and decompose your Java EE monolith • Akka Streams • Play Framework: High Velocity Web Framework for Java • jOOQ: DSL for typesafe SQL Queries • Derive4J: annotation processor for deriving algebraic data types 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  89. Java 10 (or later) Pattern matching: http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html String formatted =

    exprswitch (obj) { case Integer i -> String.format("int %d", i); case Byte b -> String.format("byte %d", b); case Long l -> String.format("long %d", l); case Double d -> String.format(“double %f", d); default -> String.format("String %s", s); }; 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)
  90. Q & A Slides & Code: https://rgra.github.io Twitter: @rgransberger Feedback

    Welcome! 08.11.2017 Øredev / Functional Java (Rabea Gransberger @rgransberger)