Il y a 13 ans -

Temps de lecture 5 minutes

Devoxx – Java Puzzlers par Joshua Bloch et William Pugh


Pour finir cette très bonne journée de jeudi, une session exceptionnelle nous attendait : Java Puzzlers par Joshua Bloch (faut-il encore le présenter ? Chief architect chez Google, Java Collections Framework, Effective Java…) et William Pugh (créateur de FindBugs) ! Ce dernier a d’ailleurs bien préparé le terrain avec la session Defective Java : Mistakes that matter qui précédait le Puzzlers.

C’est parti pour le show : les puzzlers en photo, et les remarques et solutions en commentaire !

 

Puzzler n°1

BigDecimal permet un calcul de précision que l’on ne peut avoir avec des doubles donc vous pensez tout de suite à a) ou b). En même temps, ça sent le piège car nos doubles sont toujours utilisés directement donc plutôt la c). Et bien vous avez tout faux, réponse d) !

En effet, le code passe par le constructeur public BigDecimal(double val) qui va donc représenter la valeur décimale exacte (jusque là tout va bien) d’un double à virgule flottante… donc incorrect. Et comme nous sommes en présence d’un double, nous avons la réponse d), la réponse c) étant la représentation pour un float. La solution est de passer par un String et d’utiliser ainsi le constructeur public BigDecimal(String val).

Puzzler n°2

La bonne réponse est la réponse a). La solution de ce Puzzler mériterait un article complet car beaucoup de paramètres entrent en jeux. Et ça tombe bien puisque cet article existe ! Je vous laisse donc apprécier le détail chez Alex Miller pour ce Puzzler qui s’amuse avec la méthode entrySet() d’EnumMap (même comportement pour IdentityHashMap, ConcurrentHashMap a été corrigé) et le constructeur addAll() du HashSet.

Puzzler n°3

Les solutions possibles pour ce Puzzler sont : a) 99 b) 100 c) Throws an exception d) None of above.

Et la réponse est d) avec un calcul qui va tourner très longtemps :-)

Nous sommes face à un catastrophic backtracking qui génère un calcul exponentiel pour trouver le résultat !

La solution ? Retirer le ?. Cette nouvelle RegExp (aa|aab) fonctionne exactement comme (aa|aab?) mais sans exposer ce catastrophic backtracking. Ce Puzzler n’est donc pas un bug Java mais une manière de mal écrire une RegExp.

Willian Pugh nous confirme donc que nous aurons le même problème en Ruby, Python, Perl… Joshua Bloch se demande alors Even in Scala ? Réponse de son partenaire : Yes, even in Scala ! Ce qui a bien fait rire la salle :-)

Puzzler n°4

Les solutions possibles pour ce Puzzler sont : a) ["null", null] b) [null] c) [null, null] d) None of above.

La solution est la réponse d) avec une superbe ClassCastException qui sort de nulle part ! Et bien, pas vraiment de nulle part quand on regarde de plus près. L’exception est levée dans la classe StringSink, mais il est difficile de voir quelle partie du code a pu générer une exception. En fait, ce sera même très difficile à diagnostiquer car le code qui provoque l’exception n’est pas visible ! Par contre, une fois la classe décompilée, on voit apparaître ce code non visible sous la forme d’une bridge method :

Utiliser un Generic T dans une méthode qui prend un Varargs (donc un tableau de T) a causé la création de cette méthode void add(Object a) qui retourne notre objet casté en String. En effet, le compilateur ne connaissant pas le type T (erasure mon amie…) et devant aussi gérer ce tableau, il est obligé de créer une méthode avec Object. A noter que le compilateur nous a prévenu dans les logs de compilation. Donc comme le rappelle Joshua Bloch : « Don’t ignore warnings ! ».

Puzzler n°5

Ce Puzzler est définitivement mon préféré :

Et une fois de plus, on se retrouve face à une exception, toujours de type ClassCastException. Encore un problème de Generics ? Oui… Car la classe Glommer() a été instanciée sans préciser le type T. Donc la classe passe en Raw type. Et ce qui se passe dans le cas présent, c’est que toutes les informations de Generics… sont supprimées de la classe !
Ainsi, les méthodes glom qui prenaient une Collection<?> et une List<Integer> se retrouvent désormais à recevoir une Collection et une List non typée. Comme la liste de String est instanciée avec Arrays.asList("a","b","c") qui retourne une List, la priorité va à la méthode qui prend en paramètre une List. Et devinez quoi : c’est la méthode qui initialement devait s’occuper des Integer ! D’où le ClassCastException dès la première valeur lors de la boucle (qui essaie de caster un String en int).
Dans ce cas, la solution est d’enlever ce type T de la classe (non utilisé dans le corps). La recommandation liée à ce Puzzler : n’utilisez pas les Raw Types et, une fois de plus, n’ignorez pas les warnings de compilation (car il y en aurait eu un) !

Puzzler n°6

Autant le deuxième est trouvable, autant pour le premier, tout le monde dans la salle est tombé dans le panneau (certains ont même crié « voleur, c’est pas un Puzzler ça ! »). La bonne réponse est la réponse b) avec 17777 et 43878.

Le premier calcul et le sujet du vol : ce n’est pas écrit 12345+54321 mais 12345+5432l.
Vous ne voyez toujours pas ? Je vous aide : 12345+5432L ! Et là évidemment cela change tout ! Nous n’avons donc plus 54321 mais 5432 (5432L en long) qui donne bien 17777.

Le deuxième calcul : 01234+43210 correspond en fait à 668+43210 ! Que s’est-il encore passé sous nos yeux… et bien le premier 0 de 01234 convertit notre 1234 en base 8 ! Ce qui nous donne 668 et donne une somme de 43878.

La morale de ce Puzzler : mettez des majuscules à vos long (5432L est un long et cela se voit) et ne préfixez jamais vos entiers avec un 0 à moins que vous ne vouliez vraiment le convertir en base 8.

Si ces Puzzlers vous ont plu, un seul livre : Java Puzzlers ! Un grand merci à Joshua Bloch et William Pugh pour cette excellente présentation !

Commentaire

2 réponses pour " Devoxx – Java Puzzlers par Joshua Bloch et William Pugh "

  1. Published by , Il y a 13 ans

    Excellent !

    Cependant, je n’ai pas réussi à trouver le moindre puzzler :(

    Je fais du java/jee depuis plus de 3 ans, c’est grave ?

    ++

  2. Published by , Il y a 13 ans

    Conclusion:
    – la variance des tableaux Java est cassée – ce n’est pas nouveau, mais c’est fou ce que ca peut rendre Java intéressant en terme de Puzzles. Ca reste pour moi le péché originel de Java, celui qui fait que tous les ajouts qui touchent aux types (génériques, closures, etc) sont au mieux complexes ;
    – les génériques en Java sont cassés, à cause des tableaux et d’un mélange de genre au niveau du langage (on se fiche plus ou moins qu’il y ait des types non réifiés au niveau bytecode, mais au niveau du langage > 1.5, ca ne devrait être possible) ;
    – utiliser des fonts adaptées à la programmation, c’est bien :)

    A ce sujet, quelle est votre font préférée pour coder ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.