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

  • 943 views
Uploaded on

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

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.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
943
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
12
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 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. 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. Henri Tremblay OCTO Technology Responsable R&D Performance Calcul parallèle Open Source EasyMock Objenesis
  • 4. September 2013
  • 5. September 2013
  • 6. March 2014
  • 7. March 2014
  • 8. September 2004
  • 9. Lambda return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda")));
  • 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. 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. What do I need to know? Why © OCTO 2011 12
  • 13. What do I need to know? Why Covariance © OCTO 2011 13
  • 14. What do I need to know? Why Covariance Capture © OCTO 2011 14
  • 15. What do I need to know? Why Covariance Capture Inference © OCTO 2011 15
  • 16. What do I need to know? Why Covariance Capture Inference Erasure © OCTO 2011 16
  • 17. What do I need to know? Why Covariance Capture Erasure © OCTO 2011 Inference Bridge 17
  • 18. Faire compiler 18
  • 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. Ostrich defense @SuppressWarnings("unchecked") 20
  • 21. Why © OCTO 2011 21 27 au 29 mars 2013
  • 22. Rule #1 A code compiling without warning should never ever cause a ClassCastException 22
  • 23. Covariance 23 27 au 29 mars 2013
  • 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. 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. Why for array? Integer[] list = // ... foo(list); public void foo(Object[] o) { // ... }
  • 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. 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. Exception List<?>[] l = new ArrayList<?>[3]; 29
  • 30. Capture 30 27 au 29 mars 2013
  • 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. 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. 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. Inference 34
  • 35. Diamonds are a programmer best friend List<String> l = new ArrayList<>();
  • 36. How the compiler tells the type Determine the return value type The parameter <T> T anyObject(T clazz) 36
  • 37. How the compiler tells the type The assigned variable Determine the return type MyType var = <T> T anyObject() 37
  • 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. Trick #1 Determine the return value type Artificially give the type with a dedicated parameter <T> T anyObject(Class<T> clazz) 39
  • 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. Some solutions This would work foo((String) anyObject()); foo((List<String>) anyObject()); // Warning But still doesn’t work for generics 41
  • 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. 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. Lambda = Inference return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda"));
  • 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. Trick #3: Lambda inference Object o = (Runnable) () -> { System.out.println("hi"); }; Collections.sort(strings, (String a, String b) -> a.compareTo(b));
  • 47. Erasure 47
  • 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. … 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. 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. Useful! class A {} abstract class BaseDao<T> { public T load(final long id) { // … } } class ADao extends BaseDao<A> {} © OCTO 2011 51
  • 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. Bridge © OCTO 2011 53
  • 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. But is not class B extends A { void set(String value) { this.value = value; } volatile void set(Object o){ set((String)o); } }
  • 56. Example Raw type warning Perfectly compiling A a = new B(); a.set(new Object()); But at runtime: java.lang.ClassCastException
  • 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. 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. Conclusion Who has learned something today? © OCTO 2011 59
  • 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. Conclusion Questions? http://perfug.github.io/ +Henri @henritremblay htr@octo.com © OCTO 2011 http://brownbaglunch.fr 61