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

Java 8: Lambdas and Collection Handling

Java 8: Lambdas and Collection Handling

After examining Java 8 lambdas, I came to a conclusion that they tip the scales in favor of Java; the reasons for picking one of the alternative JVM languages are not that obvious to me anymore. Not to mention the hacks required to maintain binary compatibility, Java 8 Stream API is more well-thought-out than I expected.

How to make the code more concise and readable? How do the closures work? How are the lambda types being described in method signatures? What had to be sacrificed in order to maintain binary compatibility? How the collection operations can be parallelized? Is it always beneficial?

If you want to get to know the answers, take a look at the slides: http://lukaszwrobel.pl/blog/java-8-lambdas-and-collection-handling

Lukasz Wrobel

June 17, 2015
Tweet

More Decks by Lukasz Wrobel

Other Decks in Programming

Transcript

  1. Java 8: Lambdas
    and Collection Handling
    Lukasz Wrobel

    View full-size slide

  2. About me
    • Software architect, team leader
    • Recruiter, teacher
    • High-traffic, scalable systems
    • lukaszwrobel.pl / @lukaszwrobel
    • eBook: „Memoirs of a Software Team Leader”

    View full-size slide

  3. New features
    • To me—the first breakthrough since generics.
    • Lambdas
    • @FunctionalInterface
    • default methods

    View full-size slide

  4. Implications
    • Readable collection operations
    • other languages:

    Ruby (→ Groovy), Scala, Clojure
    • DSLs
    • Parallelism

    View full-size slide

  5. Collections

    +

    lambdas
    A matter of personal importance to me

    View full-size slide

  6. Event handling

    View full-size slide

  7. At best—anonymous inner
    class
    final Button button = (Button) findViewById(R.id.button_id);
    button.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
    // Perform action on click
    }
    });

    View full-size slide

  8. How about a cleaner
    syntax?
    final Button button = (Button) findViewById(R.id.button_id);
    button.setOnClickListener((View v) -> {
    // Perform action on click
    });

    View full-size slide

  9. Collection
    manipulation

    View full-size slide

  10. Old approach
    private static int sumOfSquaresGreaterThan50(List numbers) {
    Iterator it = numbers.iterator();
    int sum = 0;
    while (it.hasNext()) {
    int number = it.next();
    int square = Math.pow(number, 2);
    if (square > 50) {
    sum += square;
    }
    }
    return sum;
    }

    View full-size slide

  11. Stream API
    private static int sumOfSquaresGreaterThan50(List numbers) {
    return numbers
    .stream()
    .mapToInt(number -> Math.pow(number, 2))
    .filter(square -> square > 50)
    .sum();
    }

    View full-size slide

  12. Intermediate vs.
    terminal
    Finish right now or add another operations the chain?

    View full-size slide

  13. Terminal operations
    • forEach[Ordered]
    • toArray
    • sorted
    • reduce
    • collect
    • min, max, sum
    • count
    • [any|all|none]Match
    • find[First|Any]

    View full-size slide

  14. Domain: cars

    View full-size slide

  15. Common use cases

    View full-size slide

  16. Filter
    public static List getInsurancedCars(ArrayList cars) {
    return cars
    .stream()
    .filter(car -> car.isInsuranced())
    .collect(Collectors.toList());
    }

    View full-size slide

  17. Method reference
    public static List getInsurancedCars(ArrayList cars) {
    return cars
    .stream()
    .filter(Car::isInsuranced)
    .collect(Collectors.toList());
    }

    View full-size slide

  18. Map
    public static List getPlates(ArrayList cars) {
    return cars
    .stream()
    .map(Car::getPlates)
    .collect(Collectors.toList());
    }

    View full-size slide

  19. Max
    public static int getTheBiggestPrice(ArrayList cars) {
    return cars
    .stream()
    .max(Car::getPrice); // Terminal operation
    }

    View full-size slide

  20. Primitives → Performance
    public static int getAverageNumberOfSeats(ArrayList cars) {
    return cars
    .stream()
    .mapToInt(Car::getNumberOfSeats)
    .average();
    }
    getAverageNumberOfSeats(allCarsInTheEntireUniverse);

    View full-size slide

  21. Variable capturing
    Either final or effectively final

    View full-size slide

  22. Final
    final Car car = new AMG("WQ 42684");
    button.setOnClickListener((View v) -> {
    displayMessage("Plates: " + car.getPlates());
    });

    View full-size slide

  23. Effectively final
    Car car = new AMG("WQ 42684");
    car = new Fiat126P("DFB 93453");
    button.setOnClickListener((View v) -> {
    displayMessage("Plates: " + car.getPlates());
    });

    View full-size slide

  24. Inline?
    public class Scrapyard {
    public List scrap(
    List cars,
    (Car -> ScrapMetal) scrapper) {
    // Scrap all the given cars
    }
    }

    View full-size slide

  25. What about type
    reuse?

    View full-size slide

  26. @FunctionalInterface
    @FunctionalInterface
    public interface Scrapper {
    ScrapMetal scrap(Car car);
    }

    View full-size slide

  27. Functional interface applied
    public class Scrapyard {
    public List scrap(
    List cars,
    Scrapper scrapper) {
    // Scrap all the given cars
    }
    }

    View full-size slide

  28. Useful functional interfaces
    Name Arguments Return type
    Function T R
    Predicate T boolean
    UnaryOperator T T
    BinaryOperator T, T T
    Supplier - T
    Consumer T void

    View full-size slide

  29. Default methods
    Binary compatibility
    Java 8 → 7 → … 1

    View full-size slide

  30. „default” keyword
    public interface AirConditioned {
    default void coolTheInterior() {
    // Perform the cooling process
    }
    }
    public class Fiat126P implements AirConditioned {
    // Thanks to the "default" keyword, Fiat 126p
    // is now being air-conditioned.
    }

    View full-size slide

  31. „default” precedence
    class > interface
    subtype > supertype
    (interfaces extending other interfaces)

    View full-size slide

  32. Effortless
    public static int getAverageNumberOfSeats(ArrayList cars) {
    return cars
    .parallelStream()
    .mapToInt(Car::getNumberOfSeats)
    .average();
    }
    getAverageNumberOfSeats(allCarsInTheEntireUniverse);

    View full-size slide

  33. Amdahl’s law
    The speedup of a program using multiple processors
    in parallel computing is limited by the time needed for
    the sequential fraction of the program.
    http://en.wikipedia.org/wiki/Amdahl%27s_law

    View full-size slide

  34. Is it worth it?
    • Number of elements:

    large enough?
    • Time spent processing each element:

    substantial?
    • Performance tests.

    View full-size slide

  35. Data structure splitting
    Performance Access type Example
    Good random ArrayList
    Bad sequential LinkedList

    View full-size slide

  36. State
    Performance State Example
    Good stateless filter
    Bad stateful sorted

    View full-size slide

  37. How is your life going
    to change?

    View full-size slide

  38. DSLs
    public class HelloWorld {
    public static void main(String[] args) {
    get("/hello", (req, res) -> „Hello, World!”);
    }
    }

    View full-size slide

  39. Caching— the old way
    public Car getCarCached(Plate plate) {
    Map cache = this.getCarCache();
    Car car = cache.get(plate);
    if (car == null) {
    car = this.getCarFromDatabase(plate);
    cache.put(plate, car);
    }
    return car;
    }

    View full-size slide

  40. Convenience
    public Car getCarCached(Plate plate) {
    return this.getCarCache()
    .computeIfAbsent(plate, this::getCarFromDatabase);
    }

    View full-size slide

  41. Thanks for listening!

    View full-size slide