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

Unleash the Power of Streams and Functional Programming in Java 8

Unleash the Power of Streams and Functional Programming in Java 8

Sergei Egorov

November 12, 2015
Tweet

More Decks by Sergei Egorov

Other Decks in Programming

Transcript

  1. LAMBDAS @bsideup Replace this… executor.submit(new Callable<String>() { @Override public String

    call() throws Exception { return "Hello!"; } }); With this! executor.submit(() -> “Hello!");
  2. SYNTAXOPTIONS Compact Much less code compared to anonymous classes One

    liners No need to use “return” for one line statements Same scope You can use “this” inside a lambda expression, they also captures variables (by making them effective final). // Inline without an argument () -> "Hello" // With code block as a body () -> { String name = "John"; return "Hello " + name; } // With parameter lastName -> "Mr. " + lastName // With explicit type of parameters (int a, int b) -> a + b @bsideup
  3. CODE List<Item> items = ...; items.stream() .filter(item -> item.getType() ==

    Type.CIRCLE) .sorted(Comparator.comparing(Item::getId)) .map(item -> "Mr. " + item.getName()) .collect(Collectors.toList()) @bsideup
  4. CODE List<Item> items = ...; items.stream() .filter(item -> item.getType() ==

    Type.CIRCLE) .sorted(Comparator.comparing(Item::getId)) .map(item -> "Mr. " + item.getName()) .collect(Collectors.toList()) @bsideup Predicate
  5. CODE List<Item> items = ...; items.stream() .filter(item -> item.getType() ==

    Type.CIRCLE) .sorted(Comparator.comparing(Item::getId)) .map(item -> "Mr. " + item.getName()) .collect(Collectors.toList()) @bsideup Comparator
  6. CODE List<Item> items = ...; items.stream() .filter(item -> item.getType() ==

    Type.CIRCLE) .sorted(Comparator.comparing(Item::getId)) .map(item -> "Mr. " + item.getName()) .collect(Collectors.toList()) @bsideup Mapper
  7. CODE List<Item> items = ...; items.stream() .filter(item -> item.getType() ==

    Type.CIRCLE) .sorted(Comparator.comparing(Item::getId)) .map(item -> "Mr. " + item.getName()) .collect(Collectors.toList()) @bsideup Collector
  8. CASE1SIMPLE @bsideup int maximum = Integer.MIN_VALUE; for (Person person :

    persons) { if (person.age() > maximum) { maximum = person.age(); } } assert maximum == maxAge;
  9. CASE1SIMPLE @bsideup int maximum = Integer.MIN_VALUE; for (Person person :

    persons) { if (person.age() > maximum) { maximum = person.age(); } } assert maximum == maxAge; int maximum = persons.stream() .mapToInt(Person::age) .max() .orElse(Integer.MIN_VALUE); assert maximum == maxAge;
  10. CASE1BENCHMARK Ops/s 1 000 10 000 100 000 1 000

    000 544 223 563232 Old Streams @bsideup Explanation Old implementation is simple For loop Streams still provide a good performance
  11. CASE2”LESS CODE” @bsideup Map<Integer, List<Person>> personsByAge = new HashMap<>(); for

    (Person person : persons) { int age = person.age(); List<Person> persons = personsByAge.get(age); if (persons == null) { persons = new ArrayList<>(); personsByAge.put(age, persons); } persons.add(person); } assert personsByAge.get(24).size() == 10;
  12. CASE2”LESS CODE” @bsideup Map<Integer, List<Person>> personsByAge = new HashMap<>(); for

    (Person person : persons) { int age = person.age(); List<Person> persons = personsByAge.get(age); if (persons == null) { persons = new ArrayList<>(); personsByAge.put(age, persons); } persons.add(person); } assert personsByAge.get(24).size() == 10; Map<Integer, List<Person>> personsByAge = persons .stream() .collect( Collectors.groupingBy(Person::age) ); assert personsByAge.get(24).size() == 10;
  13. CASE2BENCHMARK Ops/s 1 000 10 000 100 000 42966 45024

    Old Streams @bsideup Explanation Collections are already heavily optimised Streams were designed and optimised with concurrency in mind, so they can handle concurrent grouping, old code is not
  14. CASE3”LEGACY” @bsideup Map<Sex, List<Integer>> agesBySex = new HashMap<>(); for (Person

    person : persons) { List<Integer> ages = agesBySex.get(person.sex()); if (ages == null) { ages = new ArrayList<>(); agesBySex.put(person.sex(), ages); } ages.add(person.age()); } Map<Sex, Double> averageAgeBySex = new HashMap<>(); for (Map.Entry<Sex, List<Integer>> entry : agesBySex.entrySet()) { double sum = 0; for (Integer age : entry.getValue()) { sum += age; } averageAgeBySex.put(entry.getKey(), sum / (double) entry.getValue().size()); }
  15. CASE3”LEGACY” @bsideup Map<Sex, List<Integer>> agesBySex = new HashMap<>(); for (Person

    person : persons) { List<Integer> ages = agesBySex.get(person.sex()); if (ages == null) { ages = new ArrayList<>(); agesBySex.put(person.sex(), ages); } ages.add(person.age()); } Map<Sex, Double> averageAgeBySex = new HashMap<>(); for (Map.Entry<Sex, List<Integer>> entry : agesBySex.entrySet()) { double sum = 0; for (Integer age : entry.getValue()) { sum += age; } averageAgeBySex.put(entry.getKey(), sum / (double) entry.getValue().size()); } Map<Sex, Double> averageAgeBySex = persons.stream() .collect( Collectors.groupingBy( Person::sex, Collectors.averagingDouble(Person::age) ) );
  16. CASE3BENCHMARK Ops/s 0 26 667 53 333 80 000 68454

    44274 Old Streams @bsideup Explanation Not a good quality of old code, but one of the most popular ways of doing such things Heavily optimised algorithms under Stream implementation
  17. CASE4”NULL HELL” @bsideup Person person = getPersonFromCache(); if (person ==

    null) { person = getPersonFromDatabase(); if (person == null) { person = createPerson(); } } if (person != null) { blackhole.consume(person); }
  18. CASE4”NULL HELL” @bsideup Person person = getPersonFromCache(); if (person ==

    null) { person = getPersonFromDatabase(); if (person == null) { person = createPerson(); } } if (person != null) { blackhole.consume(person); } Stream.<Supplier<Person>>of( this::getPersonFromCache, this::getPersonFromDatabase, this::createPerson ) .map(Supplier::get) .filter(Objects::nonNull) .findFirst() .ifPresent(blackhole::consume);
  19. CASE4BENCHMARK Ops/s 90 000 91 500 93 000 91939 91077

    Old Streams @bsideup Explanation Magic :D JIT optimisations for Optional<T>