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
Henri Tremblay
 OCTO Technology       Open Source
    Responsable R&D      EasyMock
    Performance          Objenesis
    Calcul parallèle
September 2013
September 2013
September 2013
What do I need to know?

              Why




© OCTO 2011                 7
What do I need to know?

              Why
                    Covariance




© OCTO 2011                      8
What do I need to know?

              Why
                        Covariance

              Capture



© OCTO 2011                          9
What do I need to know?

              Why
                        Covariance

              Capture

                               Erasure

© OCTO 2011                              10
What do I need to know?

              Why
                             Covariance

              Capture

                                 Erasure
                    Bridge
© OCTO 2011                                11
What do I need to know?

              Why
                             Covariance

              Capture

                                 Erasure
                    Bridge
© OCTO 2011                                12
Lambda


 return Tweet.TWEETS.stream()
   .collect(Collectors
   .groupingBy(t->t.containsHashTag("#lambda"),
     HashMap::new, ArrayList::new));
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);
Lambda = Inférence


 return Tweet.TWEETS.stream()
   .collect( Collectors
   .groupingBy(t->t.containsHashTag("#lambda"),
     HashMap::new, ArrayList::new));
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>

© OCTO 2011                                                           16
Ostrich defense
              @SuppressWarnings("unchecked")




© OCTO 2011                              17
Why



© OCTO 2011         18
Rule #1


                  A code compiling
               without warning should
                never ever cause a
              ClassCastException
© OCTO 2011                         19
Capture



© OCTO 2011             20
Capture usually is
       Type
       List<?> bar();
       <T> IExpectationSetters<T> expect(T value);
       void andReturn(T value); // Method of IExpectationSetters
                                                            Returns a capture#6
       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>)

© OCTO 2011                                                                        21
Only solution
       We need to cast
       expect((List<String>) bar()).andReturn(new
        ArrayList<String>());       Tell to expect we want a
                                                          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
© OCTO 2011                                                              22
How the compiler tells the type
              Determine     The parameter
              the return
              value type




              <T> T anyObject(T clazz)


© OCTO 2011                                 23
How the compiler tells the type
                 The assigned   Determine the
                 variable       return type




              MyType var = <T> T anyObject()


© OCTO 2011                                     24
But watch out with overloading

       public void foo(String s)
       public void foo(Object o)

       foo(anyObject());
                           Can’t
                           guess the
                           type

© OCTO 2011                            25
Trick #1
              Determine the return   Artificially give the type with a
              value type             dedicated parameter




       <T> T anyObject(Class<T> clazz)


© OCTO 2011                                                26
But how to pass a generic?
       public void foo(String s)
       public void foo(Object o)

       foo(anyObject(List<String>.class));

                                   Examples:
                      Illegal      ToXXXFunction
© OCTO 2011                              27
Example

    • Collectors.mapping params
        •     Function, Collector
        •     ToIntFunction, Collector.OfInt
        •     ToLongFunction , Collector.OfLong
        •     ToDoubleFunction, , Collector.OfDouble



© OCTO 2011                                 28
Some solutions

                          This would work


       foo((String) anyObject());

       foo((List<String>) anyObject()); // Warning

                                     But still doesn’t work for
                                     generics
© OCTO 2011                                          29
Trick #2

       So the only solution is

       foo(EasyMock.<List<String>> anyObject());

       … which sadly doesn’t support static imports

       foo(.<List<String>> anyObject()); // Illegal


© OCTO 2011                                   30
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));
Trick #3: Lambda inference


 Object o = (Runnable) () -> {
   System.out.println("hi");
 };

 Collections.sort(strings,
   (String a, String b) -> a.compareTo(b));
Conclusion

              Who has learned
              something today?


© OCTO 2011                      33
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-4.html


 Everything on generics:
 http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
Conclusion


               Questions?



© OCTO 2011                 35

DevoxxFR 2013: Lambda are coming. Meanwhile, are you sure we've mastered the generics?

  • 1.
    Les lambda arrivent! Enattendant, ê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.
    Henri Tremblay OCTOTechnology Open Source Responsable R&D EasyMock Performance Objenesis Calcul parallèle
  • 3.
  • 4.
  • 5.
  • 7.
    What do Ineed to know? Why © OCTO 2011 7
  • 8.
    What do Ineed to know? Why Covariance © OCTO 2011 8
  • 9.
    What do Ineed to know? Why Covariance Capture © OCTO 2011 9
  • 10.
    What do Ineed to know? Why Covariance Capture Erasure © OCTO 2011 10
  • 11.
    What do Ineed to know? Why Covariance Capture Erasure Bridge © OCTO 2011 11
  • 12.
    What do Ineed to know? Why Covariance Capture Erasure Bridge © OCTO 2011 12
  • 13.
    Lambda return Tweet.TWEETS.stream() .collect(Collectors .groupingBy(t->t.containsHashTag("#lambda"), HashMap::new, ArrayList::new));
  • 14.
    Lambda = Funwith 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);
  • 15.
    Lambda = Inférence return Tweet.TWEETS.stream() .collect( Collectors .groupingBy(t->t.containsHashTag("#lambda"), HashMap::new, ArrayList::new));
  • 16.
    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> © OCTO 2011 16
  • 17.
    Ostrich defense @SuppressWarnings("unchecked") © OCTO 2011 17
  • 18.
  • 19.
    Rule #1 A code compiling without warning should never ever cause a ClassCastException © OCTO 2011 19
  • 20.
  • 21.
    Capture usually is Type List<?> bar(); <T> IExpectationSetters<T> expect(T value); void andReturn(T value); // Method of IExpectationSetters Returns a capture#6 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>) © OCTO 2011 21
  • 22.
    Only solution We need to cast expect((List<String>) bar()).andReturn(new ArrayList<String>()); Tell to expect we want a 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 © OCTO 2011 22
  • 23.
    How the compilertells the type Determine The parameter the return value type <T> T anyObject(T clazz) © OCTO 2011 23
  • 24.
    How the compilertells the type The assigned Determine the variable return type MyType var = <T> T anyObject() © OCTO 2011 24
  • 25.
    But watch outwith overloading public void foo(String s) public void foo(Object o) foo(anyObject()); Can’t guess the type © OCTO 2011 25
  • 26.
    Trick #1 Determine the return Artificially give the type with a value type dedicated parameter <T> T anyObject(Class<T> clazz) © OCTO 2011 26
  • 27.
    But how topass a generic? public void foo(String s) public void foo(Object o) foo(anyObject(List<String>.class)); Examples: Illegal ToXXXFunction © OCTO 2011 27
  • 28.
    Example • Collectors.mapping params • Function, Collector • ToIntFunction, Collector.OfInt • ToLongFunction , Collector.OfLong • ToDoubleFunction, , Collector.OfDouble © OCTO 2011 28
  • 29.
    Some solutions This would work foo((String) anyObject()); foo((List<String>) anyObject()); // Warning But still doesn’t work for generics © OCTO 2011 29
  • 30.
    Trick #2 So the only solution is foo(EasyMock.<List<String>> anyObject()); … which sadly doesn’t support static imports foo(.<List<String>> anyObject()); // Illegal © OCTO 2011 30
  • 31.
    Trick #2 appliedto 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));
  • 32.
    Trick #3: Lambdainference Object o = (Runnable) () -> { System.out.println("hi"); }; Collections.sort(strings, (String a, String b) -> a.compareTo(b));
  • 33.
    Conclusion Who has learned something today? © OCTO 2011 33
  • 34.
    Useful links Nicelambda tutorial (in French): http://lambda.ninjackaton.ninja-squad.com/ Description of inference types on lambda: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html Everything on generics: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
  • 35.
    Conclusion Questions? © OCTO 2011 35