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

Functional Libraries for Java 8+

Functional Libraries for Java 8+

Casablanca, Devoxx Morocco 2016

Rabea Gransberger

November 02, 2016
Tweet

More Decks by Rabea Gransberger

Other Decks in Programming

Transcript

  1. 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) ) 02.11.2016 2 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  2. Java 8 - Composition BiFunction<Integer, Integer, Integer> add = (x,

    y) -> x + y; BiFunction<…> addAndMultBy5 = add.andThen(x -> x * 5); addAndMultBy5.apply(2, 7); => 45 02.11.2016 3 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  3. Java 8 - Streams intList.stream() .filter(i % 2 == 0)

    .forEach(System.out::println) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 4 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
  4. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 5
  5. 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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 6
  6. 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 02.11.2016 8 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  7. 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?! • Need binary compatibility with < Java 8? => Try Retrolambda 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 9
  8. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 12
  9. 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); } 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 13
  10. 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"] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 14
  11. 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] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 15
  12. 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] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 16
  13. 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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 17
  14. 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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 18
  15. 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); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 19
  16. 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); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 21
  17. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 22
  18. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 23
  19. jOOλ - Unchecked Checked Exceptions not allowed in java.util.function Interfaces

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

    catch (IOException e) { throw new RuntimeException(e);} }) .printOut(); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 25
  21. jOOλ - Unchecked Wraps Checked Exceptions into unchecked • Runnable

    • Comparator • Consumer/BiConsumer • Function/BiFunction • Predicate/BiPredicate • Supplier • BinaryOperator / UnaryOperator • With Variants for primitives ToDoubleBiFunction etc. 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 26 Seq.of(Paths.get("D:","test.csv")) .flatMap(Unchecked.function(Files::lines)) .printOut();
  22. 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)] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 27
  23. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 28
  24. 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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 29
  25. 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)); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 30
  26. 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"))) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 31 Date Amount Balance 01.09.2016 0 11.09.2016 -20 € -20 20.09.2016 +100 € ? 27.09.2016 -5 € ?
  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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 32
  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"))) // 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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 33
  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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 34
  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) (2016-09-11, -20), (2016-09-20, 100), (2016-09-27, -5) 2016-09-11 -> (2016-09-11, -20) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 35 Window
  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) (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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 36 Window
  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) (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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 37 Window
  33. 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))) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 38
  34. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 39
  35. 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) 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 40 Date Amount Balance 01.09.2016 0 11.09.2016 -20 € -20 20.09.2016 +100 € 80 27.09.2016 -5 € 75
  36. 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] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 42
  37. Stream Utils - Example Election Time, let‘s count the votes

    02.11.2016 43 DevoxxMA / Functional Java 8 (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 }
  38. 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(); 02.11.2016 44 DevoxxMA / Functional Java 8 (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 }
  39. 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"] 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 45
  40. 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()); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 48
  41. 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(); } 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 51  not public  Meta-Annotations possible, @MyFastTag
  42. 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"); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 52
  43. 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> 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 53
  44. 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()); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 54
  45. 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));} 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 55
  46. JUnit 5 - Dynamic tests return IntStream.rangeClosed(1, 20) .map(this::fibonacci) 02.11.2016

    DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 56
  47. JUnit 5 - Dynamic tests return IntStream.rangeClosed(1, 20) .map(this::fibonacci) .mapToObj(fibo

    -> dynamicTest( "Fibonacci = " + fibo, // Name () -> testIsOdd(fibo))); // Test Body } 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 57
  48. 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 } 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 58
  49. 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 } 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 59
  50. 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); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 61
  51. AssertJ – Fluent Assertions assertThat(myName) .startsWith("Fro") .endsWith("do") .isEqualToIgnoringCase("frodo"); java.lang.AssertionError: Expecting:

    <"Rabea"> to start with: <"Fro"> 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 62
  52. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 65
  53. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 66
  54. Eclipse Collections - Primitives MutableIntList numberOfPets = this.people .sortThisByInt(p ->

    p.getNumberOfPets()) .collectInt(p -> p.getNumberOfPets()); 02.11.2016 67 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  55. Functional Programming - Recap • Functions and Values treated the

    same, pass functions around • Pure Functions: Same input => same output & no side effects List<String> values = Arrays.asList("A", "B", "C"); calculateResults(values); values => [A, B C] 02.11.2016 69 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  56. Functional Programming - Recap 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! 02.11.2016 70 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  57. Javaslang - functional library for Java 8 • Immutable &

    Persistent Collections: List, Set, Map in variations • Pure Functions • Tuple0 – 8 & Function0 – 8 • Enforces using Javaslang data structures • .toJavaStream() as bridge to Java Streams/Collections • .collector() Methods as bridge from Java Collections • Stream-like methods on all Collections: but different concept 02.11.2016 72 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  58. Javaslang – Currying Function2<Integer, Integer, Integer> sum = (a, b)

    -> a + b; Function1<Integer, Integer> add2 = sum.curried().apply(2); add2.apply(4); => 6 02.11.2016 73 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  59. Javaslang – 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 02.11.2016 74 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  60. Javaslang • Memoization: Function applied once, susequently returns same value

    Function0<Double> memo = of(Math::random) .memoized(); memo.apply() == memo.apply() • 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) 02.11.2016 75 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  61. 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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 76
  62. Javaslang - Example javaslang.collection.List<Employee> persons = … persons.filter(p -> p.getBirthday().getMonth()

    == currentMonth) .groupBy(e -> MonthDay.from(e.getBirthday())) .filter(v -> v._2.size() > 1) .forEach(JavaslangTest::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())); 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 77
  63. Javaslang - Matching String s = Match(i).of( Case(is(1), "one"), Case(is(2),

    "two"), Case($(), "?") ); 1 => one 2 => two 3 => ? 02.11.2016 78 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  64. Javaslang – 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); })) ); 02.11.2016 79 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  65. Jinq - LINQ for Java SQL: SELECT * FROM Customer

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

    -> "List read: " + list) .exceptionally(t -> "Failed: " + t.getMessage()) .thenAccept(System.out::println); 02.11.2016 84 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  67. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 86
  68. RxJava - Reactive Extensions for the JVM • Excellent Javadoc

    with Flow Diagrams of operations 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 87
  69. 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 02.11.2016 88 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  70. 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 02.11.2016 89 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  71. 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 02.11.2016 90 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  72. 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 02.11.2016 91 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  73. 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 02.11.2016 92 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  74. cyclops-react Provides reactive extensions or wraps the following libraries •

    jOOλ • RxJava • Javaslang • Pivotal Reactor • Guava • Functional Java 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 94
  75. 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 97
  76. 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"); }); 02.11.2016 98 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  77. 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()); }); 02.11.2016 99 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  78. Libraries • StreamEx • jOOλ • Stream Utils • Log4j

    2 • JUnit 5 • AssertJ • Eclipse Collections • Javaslang • RxJava • cyclops React • Vert.x • Jinq 02.11.2016 101 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)
  79. More Libraries • JDeferred: is a Java Deferred/Promise library similar

    to JQuery's Deferred Object. • 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 02.11.2016 DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger) 102
  80. Slides & Code: https://rgra.github.io Twitter: @rgransberger Feedback Welcome! 02.11.2016 103

    DevoxxMA / Functional Java 8 (Rabea Gransberger @rgransberger)