Lambdas and Generics (long version) - Bordeaux/Toulouse JUG

1,487 views

Published on

Lambda expressions are coming soon. They promise to be a nice complexity cocktail with the 9 years old generics.

Lets go deep into the generics to get a better understanding. Mix them with lambdas and wait calmly for Java 8 to arrive.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,487
On SlideShare
0
From Embeds
0
Number of Embeds
8
Actions
Shares
0
Downloads
12
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Lambdas and Generics (long version) - Bordeaux/Toulouse JUG

  1. 1. Les lambda arrivent! En attendant, êtes-vous sûr d'avoir compris les génériques? Henri Tremblay Architecte Senior OCTO Technology @henri_tremblay 27 au 29 mars 2013
  2. 2. Les lambda arrivent! En attendant, êtes-vous sûr d'avoir compris les génériques? Henri Tremblay Architecte Senior OCTO Technology @henri_tremblay 27 au 29 mars 2013
  3. 3. Henri Tremblay OCTO Technology Responsable R&D Performance Calcul parallèle Open Source EasyMock Objenesis
  4. 4. September 2013
  5. 5. September 2013
  6. 6. March 2014
  7. 7. March 2014
  8. 8. September 2004
  9. 9. Lambda return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda")));
  10. 10. 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);
  11. 11. 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);
  12. 12. What do I need to know? Why © OCTO 2011 12
  13. 13. What do I need to know? Why Covariance © OCTO 2011 13
  14. 14. What do I need to know? Why Covariance Capture © OCTO 2011 14
  15. 15. What do I need to know? Why Covariance Capture Inference © OCTO 2011 15
  16. 16. What do I need to know? Why Covariance Capture Inference Erasure © OCTO 2011 16
  17. 17. What do I need to know? Why Covariance Capture Erasure © OCTO 2011 Inference Bridge 17
  18. 18. Faire compiler 18
  19. 19. Dreaded warnings 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> 19
  20. 20. Ostrich defense @SuppressWarnings("unchecked") 20
  21. 21. Why © OCTO 2011 21 27 au 29 mars 2013
  22. 22. Rule #1 A code compiling without warning should never ever cause a ClassCastException 22
  23. 23. Covariance 23 27 au 29 mars 2013
  24. 24. Arrays Arrays are covariant: Number n = Integer.MAX_VALUE; Number[] list = new Integer[0]; Generics are not: List<Number> l = new ArrayList<Integer>(); // Illegal 24
  25. 25. 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 Would work if covariant And allow to break rule #1 25
  26. 26. Why for array? Integer[] list = // ... foo(list); public void foo(Object[] o) { // ... }
  27. 27. Arrays and generics don’t mix well Can’t have an array of generics List<String>[] lsa = new List<String>[10];// illegal 27
  28. 28. Because If it was allowed List<String>[] lsa = new List<String>[10]; // illegal Object[] oa = lsa; // OK (covariant) oa[0] = new ArrayList<Integer>(); // OK String s = lsa[0].get(0); // bad 28
  29. 29. Exception List<?>[] l = new ArrayList<?>[3]; 29
  30. 30. Capture 30 27 au 29 mars 2013
  31. 31. 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>) 31
  32. 32. 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); 32
  33. 33. Only solution We need to cast expect((List<String>) bar()).andReturn(new Tell to expect we want a ArrayList<String>()); List<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 33
  34. 34. Inference 34
  35. 35. Diamonds are a programmer best friend List<String> l = new ArrayList<>();
  36. 36. How the compiler tells the type Determine the return value type The parameter <T> T anyObject(T clazz) 36
  37. 37. How the compiler tells the type The assigned variable Determine the return type MyType var = <T> T anyObject() 37
  38. 38. But watch out with overloading public void foo(String s) public void foo(Object o) foo(anyObject()); Can’t guess the type 38
  39. 39. Trick #1 Determine the return value type Artificially give the type with a dedicated parameter <T> T anyObject(Class<T> clazz) 39
  40. 40. But how to pass a generic? public void foo(String s) public void foo(Object o) foo(anyObject(List<String>.class)); Illegal 40
  41. 41. Some solutions This would work foo((String) anyObject()); foo((List<String>) anyObject()); // Warning But still doesn’t work for generics 41
  42. 42. Trick #2 So the only solution is foo(EasyMock.<List<String>> anyObject()); … which sadly doesn’t support static imports foo(.<List<String>> anyObject()); // Illegal 42
  43. 43. Trick #2 applied to Lambda Return type: Map<Boolean, List<Tweet>> return Tweet.TWEETS.stream() .collect( Collectors.<Tweet, Boolean, List<Tweet>, Map<Boolean, List<Tweet>>> groupingBy(t->t.containsHashTag("#lambda"), HashMap::new, ArrayList::new));
  44. 44. Lambda = Inference return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda"));
  45. 45. How did he do it? List<Tweet> list = Tweet.TWEETS; Stream<Tweet> stream = list.stream(); R result = stream.collect(Collector<? super T, ?, R> collector); R result = 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); Map<Boolean, List<Tweet>> result = stream.collect(Collector<? super Tweet, ?, Map<Boolean, List<Tweet>>> collector); 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) { No type System.out.println(s); } 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 New powers unleashed! java.lang.reflect.GenericDeclaration Implemented by Class, Method, Constructor 50
  51. 51. Useful! class A {} abstract class BaseDao<T> { public T load(final long id) { // … } } class ADao extends BaseDao<A> {} © OCTO 2011 51
  52. 52. Useful! @SuppressWarnings("unchecked") public T load(final long id) { ParameterizedType type = (ParameterizedType) getClass() .getGenericSuperclass(); ADao BaseDao<A> A Type actualType = type.getActualTypeArguments()[0]; return em.find((Class<T>) actualType, (Long) id); } Unsafe cast
  53. 53. Bridge © OCTO 2011 53
  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 Raw type warning Perfectly compiling A a = new B(); a.set(new Object()); But at runtime: java.lang.ClassCastException
  57. 57. The actual problem being B.class.getDeclaredMethods() This Returns that volatile void set(java.lang.Object) void B.set(java.lang.String) 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? © OCTO 2011 59
  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
  61. 61. Conclusion Questions? http://perfug.github.io/ +Henri @henritremblay htr@octo.com © OCTO 2011 http://brownbaglunch.fr 61

×