Lambdas and Generics (long version) - Bordeaux/Toulouse JUG
Oct. 19, 2013•0 likes•1,912 views
Report
Technology
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.
Lambdas and Generics (long version) - Bordeaux/Toulouse JUG
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
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
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
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
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
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
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
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));
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
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
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
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