O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Java 8, lambdas, generics: How to survive? - NYC Java Meetup Group

952 visualizações

Publicada em

Lambdas are sexy. But they are adding complexity. Mixed with generics, it creates a dangerous cocktail. Together, we will start from the bottom of generics and go straight through lambda inference. To explain why it is the way it is and tell you how to survive.

Publicada em: Software
  • Seja o primeiro a comentar

Java 8, lambdas, generics: How to survive? - NYC Java Meetup Group

  1. 1. 27 au 29 mars 2013 Java 8, Lambdas, Generics: How to survive? Henri Tremblay Java Champion tremblay.pro inc. @henri_tremblay http://blog.tremblay.pro NYC Java Meetup Group
  2. 2. Loves IT Strategy Performance Productivity Great food! Do Open Source Henri Tremblay Try to be useful
  3. 3. September 2004
  4. 4. March 18 2014
  5. 5. Java 7 End of Life
  6. 6. Java 8 support
  7. 7. Lambda return Tweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda")));
  8. 8. 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);
  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. Compiled successfully! 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://www.montreal- jug.org/ http://brownbaglunch.fr @henri_tremblay http://blog.tremblay.pro henri@tremblay.pro

×