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

3ea55d185aee5756c52056419238eec8?s=128

Lukasz Wrobel

June 17, 2015
Tweet

Transcript

  1. Java 8: Lambdas and Collection Handling Lukasz Wrobel

  2. About me • Software architect, team leader • Recruiter, teacher

    • High-traffic, scalable systems • lukaszwrobel.pl / @lukaszwrobel • eBook: „Memoirs of a Software Team Leader”
  3. New features • To me—the first breakthrough since generics. •

    Lambdas • @FunctionalInterface • default methods
  4. Implications • Readable collection operations • other languages:
 Ruby (→

    Groovy), Scala, Clojure • DSLs • Parallelism
  5. Collections
 +
 lambdas A matter of personal importance to me

  6. Event handling

  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 } });
  8. How about a cleaner syntax? final Button button = (Button)

    findViewById(R.id.button_id); button.setOnClickListener((View v) -> { // Perform action on click });
  9. Collection manipulation

  10. Old approach private static int sumOfSquaresGreaterThan50(List<Integer> numbers) { Iterator<Integer> 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; }
  11. Stream API private static int sumOfSquaresGreaterThan50(List<Integer> numbers) { return numbers

    .stream() .mapToInt(number -> Math.pow(number, 2)) .filter(square -> square > 50) .sum(); }
  12. Intermediate vs. terminal Finish right now or add another operations

    the chain?
  13. Terminal operations • forEach[Ordered] • toArray • sorted • reduce

    • collect • min, max, sum • count • [any|all|none]Match • find[First|Any]
  14. Domain: cars

  15. Common use cases

  16. Filter public static List<Car> getInsurancedCars(ArrayList<Car> cars) { return cars .stream()

    .filter(car -> car.isInsuranced()) .collect(Collectors.toList()); }
  17. Method reference public static List<Car> getInsurancedCars(ArrayList<Car> cars) { return cars

    .stream() .filter(Car::isInsuranced) .collect(Collectors.toList()); }
  18. Map public static List<Plates> getPlates(ArrayList<Car> cars) { return cars .stream()

    .map(Car::getPlates) .collect(Collectors.toList()); }
  19. Max public static int getTheBiggestPrice(ArrayList<Car> cars) { return cars .stream()

    .max(Car::getPrice); // Terminal operation }
  20. Primitives → Performance public static int getAverageNumberOfSeats(ArrayList<Car> cars) { return

    cars .stream() .mapToInt(Car::getNumberOfSeats) .average(); } getAverageNumberOfSeats(allCarsInTheEntireUniverse);
  21. Variable capturing Either final or effectively final

  22. Final final Car car = new AMG("WQ 42684"); button.setOnClickListener((View v)

    -> { displayMessage("Plates: " + car.getPlates()); });
  23. Effectively final Car car = new AMG("WQ 42684"); car =

    new Fiat126P("DFB 93453"); button.setOnClickListener((View v) -> { displayMessage("Plates: " + car.getPlates()); });
  24. Lambda type

  25. None
  26. Inline? public class Scrapyard { public List<ScrapMetal> scrap( List<Car> cars,

    (Car -> ScrapMetal) scrapper) { // Scrap all the given cars } }
  27. What about type reuse?

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

  29. Functional interface applied public class Scrapyard { public List<ScrapMetal> scrap(

    List<Car> cars, Scrapper scrapper) { // Scrap all the given cars } }
  30. Useful functional interfaces Name Arguments Return type Function<T, R> T

    R Predicate<T> T boolean UnaryOperator<T> T T BinaryOperator<T> T, T T Supplier<T> - T Consumer<T> T void
  31. Default methods Binary compatibility Java 8 → 7 → …

    1
  32. „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. }
  33. None
  34. „default” precedence class > interface subtype > supertype (interfaces extending

    other interfaces)
  35. Parallelism

  36. Effortless public static int getAverageNumberOfSeats(ArrayList<Car> cars) { return cars .parallelStream()

    .mapToInt(Car::getNumberOfSeats) .average(); } getAverageNumberOfSeats(allCarsInTheEntireUniverse);
  37. However…

  38. 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
  39. Is it worth it? • Number of elements:
 large enough?

    • Time spent processing each element:
 substantial? • Performance tests.
  40. Data structure splitting Performance Access type Example Good random ArrayList

    Bad sequential LinkedList
  41. State Performance State Example Good stateless filter Bad stateful sorted

  42. How is your life going to change?

  43. DSLs public class HelloWorld { public static void main(String[] args)

    { get("/hello", (req, res) -> „Hello, World!”); } }
  44. Caching— the old way public Car getCarCached(Plate plate) { Map<Plate,

    Car> cache = this.getCarCache(); Car car = cache.get(plate); if (car == null) { car = this.getCarFromDatabase(plate); cache.put(plate, car); } return car; }
  45. Convenience public Car getCarCached(Plate plate) { return this.getCarCache() .computeIfAbsent(plate, this::getCarFromDatabase);

    }
  46. Thanks for listening!