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
Loves
IT Strategy
Performance
Productivity
Great food!
Do Open Source
Henri Tremblay
Try to be useful
September 2004
March 18 2014
Java 7 End of Life
Java 8 support
Lambda
return Tweet.TWEETS.stream()
.collect(Collectors
.partitioningBy(
t->t.containsHashTag("#lambda")));
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);
What do I need to know?
9© OCTO 2011
Why
What do I need to know?
10© OCTO 2011
Why
Covariance
What do I need to know?
11© OCTO 2011
Why
Covariance
Capture
What do I need to know?
12© OCTO 2011
Why
Covariance
Capture
Inference
What do I need to know?
13© OCTO 2011
Why
Covariance
Capture
Inference
Erasure
What do I need to know?
14© OCTO 2011
Why Covariance
Capture Inference
Erasure Bridge
Compiled successfully!
15
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>
Ostrich defense
@SuppressWarnings("unchecked")
17
27 au 29 mars 2013
Why
18© OCTO 2011
Rule #1
A code compiling
without warning should
never ever cause a
ClassCastException
19
27 au 29 mars 2013
Covariance
20
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
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
Why for array?
Integer[] list = // ...
foo(list);
public void foo(Object[] o) {
// ...
}
Arrays and generics don’t mix well
Can’t have an array of generics
List<String>[] lsa = new List<String>[10];// illegal
24
Exception
List<?>[] l = new ArrayList<?>[3];
25
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 au 29 mars 2013
Capture
27
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
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
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>
Inference
31
Diamonds are a programmer best friend
List<String> l = new ArrayList<>();
How the compiler tells the type
<T> T anyObject(T clazz)
33
The parameterDetermine
the return
value type
How the compiler tells the type
MyType var = <T> T anyObject()
34
Determine the
return type
The assigned
variable
But watch out with overloading
public void foo(String s)
public void foo(Object o)
foo(anyObject());
35
Can’t
guess the
type
Trick #1
<T> T anyObject(Class<T> clazz)
36
Artificially give the type with a
dedicated parameter
Determine the return
value type
But how to pass a generic?
public void foo(String s)
public void foo(Object o)
foo(anyObject(List<String>.class));
37
Illegal
Some solutions
foo((String) anyObject());
foo((List<String>) anyObject()); // Warning
38
This would work
But still doesn’t work for
generics
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
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>>
Lambda = Inference
return Tweet.TWEETS.stream()
.collect(Collectors
.partitioningBy(
t->t.containsHashTag("#lambda"));
How did it do it?
Tweet.TWEETS.stream()
List<Tweet> list = Tweet.TWEETS;
Stream<Tweet> stream = list.stream();
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);
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);
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");
Trick #3: Lambda inference
Object o = (Runnable) () -> {
System.out.println("hi");
};
Collections.sort(strings,
(String a, String b) -> a.compareTo(b));
Erasure
47
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
… 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
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!
Useful!
class A {}
abstract class BaseDao<T> {
public T load(final long id) {
// …
}
}
class ADao extends BaseDao<A> {}
51© OCTO 2011
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
Bridge
53© OCTO 2011
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;
}
}
But is not
class B extends A {
void set(String value) {
this.value = value;
}
volatile void set(Object o){
set((String)o);
}
}
Example
A a = new B();
a.set(new Object());
But at runtime:
java.lang.ClassCastException
Raw type warning Perfectly compiling
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
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
Conclusion
Who has learned
something today?
59© OCTO 2011
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/
Conclusion
Questions?
61© OCTO 2011
http://www.montreal-
jug.org/
http://brownbaglunch.fr
@henri_tremblay
http://blog.tremblay.pro
henri@tremblay.pro

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

  • 1.
    27 au 29mars 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.
    Loves IT Strategy Performance Productivity Great food! DoOpen Source Henri Tremblay Try to be useful
  • 3.
  • 4.
  • 5.
    Java 7 Endof Life
  • 6.
  • 7.
  • 8.
    Lambda = Funwith 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.
    What do Ineed to know? 9© OCTO 2011 Why
  • 10.
    What do Ineed to know? 10© OCTO 2011 Why Covariance
  • 11.
    What do Ineed to know? 11© OCTO 2011 Why Covariance Capture
  • 12.
    What do Ineed to know? 12© OCTO 2011 Why Covariance Capture Inference
  • 13.
    What do Ineed to know? 13© OCTO 2011 Why Covariance Capture Inference Erasure
  • 14.
    What do Ineed to know? 14© OCTO 2011 Why Covariance Capture Inference Erasure Bridge
  • 15.
  • 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.
  • 18.
    27 au 29mars 2013 Why 18© OCTO 2011
  • 19.
    Rule #1 A codecompiling without warning should never ever cause a ClassCastException 19
  • 20.
    27 au 29mars 2013 Covariance 20
  • 21.
    Arrays Arrays are covariant: Numbern = Integer.MAX_VALUE; Number[] list = new Integer[0]; Generics are not: List<Number> l = new ArrayList<Integer>(); // Illegal 21
  • 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.
    Why for array? Integer[]list = // ... foo(list); public void foo(Object[] o) { // ... }
  • 24.
    Arrays and genericsdon’t mix well Can’t have an array of generics List<String>[] lsa = new List<String>[10];// illegal 24
  • 25.
    Exception List<?>[] l =new ArrayList<?>[3]; 25
  • 26.
    Because If it wasallowed 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 au 29mars 2013 Capture 27
  • 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.
    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.
    Only solution We needto 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.
  • 32.
    Diamonds are aprogrammer best friend List<String> l = new ArrayList<>();
  • 33.
    How the compilertells the type <T> T anyObject(T clazz) 33 The parameterDetermine the return value type
  • 34.
    How the compilertells the type MyType var = <T> T anyObject() 34 Determine the return type The assigned variable
  • 35.
    But watch outwith overloading public void foo(String s) public void foo(Object o) foo(anyObject()); 35 Can’t guess the type
  • 36.
    Trick #1 <T> TanyObject(Class<T> clazz) 36 Artificially give the type with a dedicated parameter Determine the return value type
  • 37.
    But how topass a generic? public void foo(String s) public void foo(Object o) foo(anyObject(List<String>.class)); 37 Illegal
  • 38.
    Some solutions foo((String) anyObject()); foo((List<String>)anyObject()); // Warning 38 This would work But still doesn’t work for generics
  • 39.
    Trick #2 So theonly solution is foo(EasyMock.<List<String>> anyObject()); … which sadly doesn’t support static imports foo(.<List<String>> anyObject()); // Illegal 39
  • 40.
    Trick #2 appliedto 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.
    Lambda = Inference returnTweet.TWEETS.stream() .collect(Collectors .partitioningBy( t->t.containsHashTag("#lambda"));
  • 42.
    How did itdo it? Tweet.TWEETS.stream() List<Tweet> list = Tweet.TWEETS; Stream<Tweet> stream = list.stream();
  • 43.
    How did itdo 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.
    How did itdo 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.
    How did itdo 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.
    Trick #3: Lambdainference Object o = (Runnable) () -> { System.out.println("hi"); }; Collections.sort(strings, (String a, String b) -> a.compareTo(b));
  • 47.
  • 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.
    … or noterasure 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 java.lang.reflect.GenericDeclaration Implemented by Class, Method, Constructor 50 New powers unleashed!
  • 51.
    Useful! class A {} abstractclass BaseDao<T> { public T load(final long id) { // … } } class ADao extends BaseDao<A> {} 51© OCTO 2011
  • 52.
    Useful! @SuppressWarnings("unchecked") public T load(finallong 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.
  • 54.
    Everything seems normal… classA<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 classB extends A { void set(String value) { this.value = value; } volatile void set(Object o){ set((String)o); } }
  • 56.
    Example A a =new B(); a.set(new Object()); But at runtime: java.lang.ClassCastException Raw type warning Perfectly compiling
  • 57.
    The actual problembeing 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.
    What about lambdas? publicclass 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.
  • 60.
    Useful links Nice lambdatutorial (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.

Editor's Notes

  • #8 Hors le fait que ça nous donne des magnifiques oneliners, on y croise une quantité particulièrement épique de génériques
  • #9 Malheureusement, quand on le sépare en petits morceaux, nous voyons apparaître des tonnes de génériques. La bonne nouvelle, c’est que ça s’est amélioré. La dernière fois que j’ai donné cette conférence, ça ressemblait plutôt à ça
  • #10 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #11 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #12 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #13 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #14 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #15 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #16 Emplit de désespoir vous ne savez pas trop comment vous en débarasser parce que toutes vos tentatives ne compilent pas.
  • #17 Emplit de désespoir vous ne savez pas trop comment vous en débarasser parce que toutes vos tentatives ne compilent pas.
  • #18 Et vous terminez, pas trop fier de vous et pas trop sûr d’avoir compris le problème avec un aborable SuppressWarning. Cette session a pour but de vous faire comprendre 1- Pourquoi vous avez ces erreurs 2- Pourquoi c’est fait comme ça 3- Comment c’est implémenté
  • #19 Par exemple, les arrays
  • #20 C’est cette règle qui a forcé plusieurs décisions de design et qui a par conséquent rendu notre ami le @SuppressWarning si fréquent. On en vient à ce demander comment ils auraient fait si les annotations n’étaient pas apparu au même moment.
  • #21 Par exemple, les arrays
  • #22 Les arrays sont covariants. Si on peut assigner un object d’un type donné à un autre type, alors on peut assigner un array d’objet à un array de l’autre type Par contre pour les génériques on ne peut pas. Il est illégal de faire la ligne du bas. Car, un code qui compile sans warning ne doit jamais jamais causé un ClassCastException
  • #23 Un exemple que vous avez sûrement déjà vu pour expliquer pourquoi c’est interdit. Comme vous voyez, si la covariance était permisse nous briserions la règle #1 Et pour un array
  • #24 Parce que pour un tableau, on a envie que ça ça passe
  • #25 On ne peut pas faire de tableau de génériques et c’est bien dommage. Une seule exception, un tableau de wildcard. Le wildcard étant un type quelconque, nous n’avons pas de soucis. Dans tous les autres cas c’est interdit pour la raison suivante
  • #26 On ne peut pas faire de tableau de génériques et c’est bien dommage. Une seule exception, un tableau de wildcard. Le wildcard étant un type quelconque, nous n’avons pas de soucis. Dans tous les autres cas c’est interdit pour la raison suivante
  • #27 Nous avons le cas suivant. Grâce une asticieuse utilisation de la covariance des arrays, si les arrays génériques étaient permis, nous briserions la règle numéro 1. En résumé, si les designers des génériques avaient laissé tomber la règle pour ce cas et laisser le bénéfice du doute au développeur, nous aurions échappé à plusieurs complexité. Je vous laisse juge de leur décision.
  • #28 Par exemple, les arrays
  • #29 Une méthode retourne un type en wildcard Pour garder la cohérence, le compilateur va fixer le type et l’appeler capture#6 pour s’assurer de la cohérence du type donné à T Pour les développeurs de framework, ne jamais retourner de wildcard si possible
  • #30 Une méthode retourne un type en wildcard Pour garder la cohérence, le compilateur va fixer le type et l’appeler capture#6 pour s’assurer de la cohérence du type donné à T Pour les développeurs de framework, ne jamais retourner de wildcard si possible
  • #31 Warning mandatory pour ne pas enfreindre la règle #1
  • #32 Par exemple, les arrays
  • #34 Lorsqu’il y a un paramètre, le compilateur prend le type du paramètre pour déterminer le type de retour. Cette pour cette raison que le syntaxe que vous voyez est apparu en Java 5. Le paramètre ne sert à rien sauf à fixer le type. Mais ça vous les savez sûrement déjà.
  • #35 Ensuite s’il n’y a pas de paramètre, le compilateur déduit le type à partir de la variable à laquelle elle est assignée. Mais ça ne marche pas à tous les coups.
  • #36 Dans les cas d’overloading par exemple. Impossible de deviner quelle méthode doit être appelé
  • #37 Un truc classique est d’ajouter un paramètre juste pour la bonne cause. C’est un contournement classique.
  • #38 Dans les cas d’overloading par exemple. Impossible de deviner quelle méthode doit être appelé
  • #41 Pour les lambda, il est très fort probable d’en avoir besoin. Vous avez ici l’exemple du début où je l’utilisais. Fort heureusement, ce n’est pas nécessaire dans la nouvelle API. Par contre, j’ai un peu de difficulté à vous promettre que ce sera toujours le cas. On touche du bois
  • #48 Par exemple, les arrays
  • #49 Everybody knows what is erasure? List<String> and ArrayList<String> got erasure The variable in the loop kept is type Boring, nous on va parler des cas où il n’y a pas d’erasure.
  • #50 Oh dear, no erasure On récupère la classe parent qui s’avère être générique et implémente donc l’interface ParameterizedType.
  • #51 Il y a eu un ajout de plusieurs interfaces. Elles sont passées presque complètement inaperçu mais peuvent être utile. Par exemple, l’exemple précédent peut servir à faire ça
  • #53 Par polymorphisme, le getClass() retourne ADao. Donc la superclass est BaseDao, et le type du paramètre générique est A. And yes, the dumb part if the SuppressWarnings. It comes come the (Class<T>) cast. Since the compiler can’t be sure that actualType is a Class, we get the warning. On ne peut pas s’en débarasser.
  • #54 Par exemple, les arrays
  • #55 Vous avez une classe générique étendue par un autre qui fixe le type à String. Rien de plus classique.
  • #56 Magie, à la décompilation, une nouvelle méthode est apparue. C’est le bridge. Elle ne sert à rien sauf à l’assurer c’est bien une String qui est passé en paramètre. Le volatile c’est parce que la modificateur de champs et de méthodes ont des codes communs. Donc en fait, le décompilateur (jad) a un petit bogue. Attention, Java Decompiler ne vous montrera pas le bridge, il le fait disparaitre. On ne le voit qu’avec Jad qui est moins futé.
  • #57 La règle #1 n’est pas enfreinte car nous avons un warning. Par contre, Java ajoute dans ce cas particulier une sur-protection. Impossible de s’en prémunir à la compilation. Tout est valide. Il fallait donc combler la faille pour empêcher un Object d’être assigné à une String et amener le chaos et l’anarchie dans la JVM. D’où, le bridge.
  • #58 Vous avez deux méthodes. L’une déléguant directement à l’autre. Si vous avez un framework faisant des proxies dynamiques ou de l’AOP, vous vous retrouvez avec deux méthodes instrumentées. Et c’est assez rare que c’est ce que vous aviez prévus. Résultat, plus rien ne marche. Par exemple, Spring qui utilise beaucoup de proxies, a dû implémenter une class nommée BridgeMethodResolver qui permet de trouver la méthode concrête appelée par le bridge. Et malheureusement, le JDK n’a pas prévu le coup donc il faut la déduire. C’est ce que j’avais de plus compliqué à vous montrer aujourd’hui. Passons donc à la conclusion.
  • #60 J’ai pas mal pataugé sur ces sujets car ils sont assez peu documentés. C’est pas simple mais on finit par s’y retrouver. La question qui me taraude maintenant c’est “Est-ce que vous connaissiez tout ça?” Pour m’assurez que je ne raconte pas que des banalités. Est-ce que chaque personne pourrait lever la main et me dire si vous avez appris au moins une chose aujourd’hui?
  • #61 Maurice Naftalin
  • #62 Oh dear, no erasure