Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Generics and Lambdas cocktail explained - Montreal JUG

1 274 vues

Publié le

We are in 2015 and Java 8 will slowly but surely become the new standard. Our world will be filled with lambdas. Generics, for themselves, have appeared in 2004. They brought benefits and complexity. Enough to blow up the complexity quota of Java according to Josh Bloch.

But lambdas, whatever are sexy they are, are going to add even more complexity. Mix with generics your now playing with nitroglycerin.

We will travel together through the bottom of the generics, through inference and through lambdas type resolution. To explain why. To provide solutions. To ease Java 8 adoption.

Publié dans : Technologie
  • Soyez le premier à commenter

Generics and Lambdas cocktail explained - Montreal JUG

  1. 1. 27 au 29 mars 2013 Les lambda sont là! Mais êtes-vous sûr d'avoir compris les génériques? Henri Tremblay Architecte Senior Pages Jaunes @henri_tremblay
  2. 2. Amateur de Stratégie TI Performance Productivité Bons vins, bières, whiskies… Fait de l’Open Source Henri Tremblay Aime être utile
  3. 3. March 18 2014
  4. 4. Java 7 End of Life
  5. 5. September 2004
  6. 6. Lambda return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda")));
  7. 7. Lambda = Fun with generics Stream<Tweet> stream = Tweet.TWEETS.stream(); Predicate<Tweet> lambda = t -> t.containsHashTag("#lambda"); Collector<Tweet, ?, Map<Boolean, List<Tweet>>> collector = Collectors.partitioningBy(lambda); return stream.collect(collector);
  8. 8. Lambda = Fun with generics Stream<Tweet> stream = Tweet.TWEETS.stream(); Function<Tweet, Boolean> lambda = t -> t.containsHashTag("#lambda"); Collector<Tweet, Map<Boolean, List<Tweet>>> collector = Collectors.<Tweet, Boolean, List<Tweet>, Map<Boolean, List<Tweet>>> groupingBy(lambda, HashMap::new, ArrayList::new); return stream.collect(collector);
  9. 9. What do I need to know? 9© OCTO 2011 Why
  10. 10. What do I need to know? 10© OCTO 2011 Why Covariance
  11. 11. What do I need to know? 11© OCTO 2011 Why Covariance Capture
  12. 12. What do I need to know? 12© OCTO 2011 Why Covariance Capture Inference
  13. 13. What do I need to know? 13© OCTO 2011 Why Covariance Capture Inference Erasure
  14. 14. What do I need to know? 14© OCTO 2011 Why Covariance Capture Inference Erasure Bridge
  15. 15. Faire compiler 15
  16. 16. Dreaded warnings 16 Type safety: The expression of type List needs unchecked conversion to conform to List<String> Type safety: Unchecked cast from List<capture#1-of ?> to List<String>
  17. 17. Ostrich defense @SuppressWarnings("unchecked") 17
  18. 18. 27 au 29 mars 2013 Why 18© OCTO 2011
  19. 19. Rule #1 A code compiling without warning should never ever cause a ClassCastException 19
  20. 20. 27 au 29 mars 2013 Covariance 20
  21. 21. Arrays Arrays are covariant: Number n = Integer.MAX_VALUE; Number[] list = new Integer[0]; Generics are not: List<Number> l = new ArrayList<Integer>(); // Illegal 21
  22. 22. Why not? List<Integer> li = new ArrayList<Integer>(); List<Number> ln = li; // illegal ln.add(new Float(3.1415)); int i = li.get(0); // ClassCastException 22 Would work if covariant And allow to break rule #1
  23. 23. Why for array? Integer[] list = // ... foo(list); public void foo(Object[] o) { // ... }
  24. 24. Arrays and generics don’t mix well Can’t have an array of generics List<String>[] lsa = new List<String>[10];// illegal 24
  25. 25. Exception List<?>[] l = new ArrayList<?>[3]; 25
  26. 26. Because If it was allowed List<String>[] lsa = new List<String>[10]; // illegal Object[] oa = lsa; // OK (covariant) oa[0] = new ArrayList<Integer>(); // OK oa[0].add(42); String s = lsa[0].get(0); // bad 26
  27. 27. 27 au 29 mars 2013 Capture 27
  28. 28. Capture usually is Type List<?> bar(); <T> IExpectationSetters<T> expect(T value); void andReturn(T value); // Method of IExpectationSetters expect(bar()).andReturn(new ArrayList<String>()); And you get The method andReturn(List<capture#6-of ?>) in the type IExpectationSetters<List<capture#6-of ?>> is not applicable for the arguments (ArrayList<String>) 28
  29. 29. Detail List<?> bar(); <T> IExpectationSetters<T> expect(T value); void andReturn(T value); expect(bar()).andReturn(new ArrayList<String>()); List<Capture#6> bar = bar(); IExpectationSetters<List<Capture#6>> es = expect(bar()); es.andReturn(List<Capture#6> value); 29
  30. 30. Only solution We need to cast expect((List<String>) bar()).andReturn(new ArrayList<String>()); But still a warning Type safety: Unchecked cast from List<capture#6-of ?> to List<String> Framework coder tip: Try to never return a wildcard unless necessary 30 Tell to expect we want a List<String>
  31. 31. Inference 31
  32. 32. Diamonds are a programmer best friend List<String> l = new ArrayList<>();
  33. 33. How the compiler tells the type <T> T anyObject(T clazz) 33 The parameterDetermine the return value type
  34. 34. How the compiler tells the type MyType var = <T> T anyObject() 34 Determine the return type The assigned variable
  35. 35. But watch out with overloading public void foo(String s) public void foo(Object o) foo(anyObject()); 35 Can’t guess the type
  36. 36. Trick #1 <T> T anyObject(Class<T> clazz) 36 Artificially give the type with a dedicated parameter Determine the return value type
  37. 37. But how to pass a generic? public void foo(String s) public void foo(Object o) foo(anyObject(List<String>.class)); 37 Illegal
  38. 38. Some solutions foo((String) anyObject()); foo((List<String>) anyObject()); // Warning 38 This would work But still doesn’t work for generics
  39. 39. Trick #2 So the only solution is foo(EasyMock.<List<String>> anyObject()); … which sadly doesn’t support static imports foo(.<List<String>> anyObject()); // Illegal 39
  40. 40. Trick #2 applied to Lambda return Tweet.TWEETS.stream() .collect( Collectors.<Tweet, Boolean, List<Tweet>, Map<Boolean, List<Tweet>>> groupingBy(t->t.containsHashTag("#lambda"), HashMap::new, ArrayList::new)); Return type: Map<Boolean, List<Tweet>>
  41. 41. Lambda = Inference return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda"));
  42. 42. How did it do it? Tweet.TWEETS.stream() List<Tweet> list = Tweet.TWEETS; Stream<Tweet> stream = list.stream();
  43. 43. How did it do it? Stream<Tweet> stream = list.stream(); R result = stream.collect(Collector<? super T, ?, R> collector); R result = stream.collect(Collector<? super Tweet, ?, R> collector);
  44. 44. How did it do it? stream.collect(Collector<? super Tweet, ?, R> collector); Collector<T, ?, Map<Boolean, List<T>>> collector = Collectors.partitioningBy(Predicate<? super T> predicate); Collector<Tweet, ?, Map<Boolean, List<Tweet>>> collector = Collectors.partitioningBy(Predicate<? super Tweet> predicate);
  45. 45. How did it do it? Predicate<? super Tweet> lambda = t -> t.containsHashTag("#lambda"); We now know that So the best t can be is a Tweet Predicate<? super Tweet> lambda = (Tweet t) -> t.containsHashTag("#lambda");
  46. 46. Trick #3: Lambda inference Object o = (Runnable) () -> { System.out.println("hi"); }; Collections.sort(strings, (String a, String b) -> a.compareTo(b));
  47. 47. Erasure 47
  48. 48. Erasure… public void foo() { List<String> l = new ArrayList<String>(); for (String s : l) { System.out.println(s); } } No type public void foo() { List l = new ArrayList(); for (String s : l) { System.out.println(s); } } Compilation
  49. 49. … or not erasure public class A extends ArrayList<String> {} public static void main(final String[] args) { ParameterizedType type = (ParameterizedType) A.class.getGenericSuperclass(); System.out.println( type.getActualTypeArguments()[0]); }  prints class java.lang.String 49
  50. 50. Type class java.lang.reflect.Type • GenericArrayType • ParameterizedType • TypeVariable • WildcardType • Implemented by Class java.lang.reflect.GenericDeclaration Implemented by Class, Method, Constructor 50 New powers unleashed!
  51. 51. Useful! class A {} abstract class BaseDao<T> { public T load(final long id) { // … } } class ADao extends BaseDao<A> {} 51© OCTO 2011
  52. 52. Useful! @SuppressWarnings("unchecked") public T load(final long id) { ParameterizedType type = (ParameterizedType) getClass() .getGenericSuperclass(); Type actualType = type.getActualTypeArguments()[0]; return em.find((Class<T>) actualType, (Long) id); } ADao A BaseDao<A> Unsafe cast
  53. 53. Bridge 53© OCTO 2011
  54. 54. Everything seems normal… class A<T> { abstract void set(T value); } class B extends A<String> { String value; @Override void set(final String value) { this.value = value; } }
  55. 55. But is not class B extends A { void set(String value) { this.value = value; } volatile void set(Object o){ set((String)o); } }
  56. 56. Example A a = new B(); a.set(new Object()); But at runtime: java.lang.ClassCastException Raw type warning Perfectly compiling
  57. 57. The actual problem being B.class.getDeclaredMethods() volatile void set(java.lang.Object) void B.set(java.lang.String) This Returns that And gives you no way to find out which method is bridged
  58. 58. What about lambdas? public class A { public static void main(String[] args) { Method[] methods = A.class.getDeclaredMethods(); Arrays.stream(methods).forEach(m -> System.out.println(m + " " + m.isBridge() + " " + m.isSynthetic())); } } Prints this public static void A.main(java.lang.String[]) false false private static void A.lambda$0(java.lang.reflect.Method) false true
  59. 59. Conclusion Who has learned something today? 59© OCTO 2011
  60. 60. Useful links Nice lambda tutorial (in French): http://lambda.ninjackaton.ninja-squad.com/ Description of inference types on lambda: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html Everything on generics: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html Hopefully everything on lambdas http://www.lambdafaq.org/
  61. 61. Conclusion Questions? 61© OCTO 2011 http://perfug.github.io/ http://brownbaglunch.fr +Henri Tremblay @henri_tremblay henri@tremblay.pro

×