Java : quizz #2

Question : que se passera-t-il avec le code ci-dessous ?

List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();

for (Iterator i = suits.iterator(); i.hasNext(); )
    for (Iterator j = ranks.iterator(); j.hasNext(); )
        sortedDeck.add(new Card(i.next(), j.next()));

A : rien, le code s'exécute correctement
B : le code ne se compile pas
C : le code ne s'exécute pas
D : une exception sera levée pendant l'execution

=== Réponse : on peut compiler et executer le code sans problème. 
Cependant à l'execution si la liste "suits" ne contient pas assez d'éléments 
pour les 2 boucles imbriquées, on aura alors une NoSuchElementException car
la méthode "i.next()" de la liste "suits" sera appelée "trop" de fois (on sera arrivé
à la fin de la liste "suits" avant celle de la liste "ranks")

Java varargs – Pas de magie: soyez prudents!

J’ai rencontré une erreur bizarre, liée aux varargs, sur un projet que je visitais récemment…

Tout d’abord un petit rappel de ce que sont les varargs en java:
Comme vous le savez surement les varargs permettent de définir des méthodes qui peuvent accepter des arguments optionnels et au nombre variable. Définir une telle méthode est aussi simple que ci-dessous:

public void doSomething(String... values) {
// do something here
}

La méthode est alors accessible avec aucun paramètre ou n’importe quel nombre de paramètres:

public void callDoSomething() {
doSomething();
doSomething("a","b","c");
}

Bref les varargs apportent une vrai souplesse dans la définition et l’utilisation des méthodes aux paramètres optionnels et/ou variables en java.
Maintenant que ce passe-t-il réellement ? Comment JAVA gère cette magie ? En fait la réalité est relativement simple et peut-être pas aussi idéale que ce qu’on aurait pu le souhaiter… En effet les varargs ne sont pas une nouvelle super feature de java mais plutôt une feature de son compilateur. Le compilateur va tout simplement remplacer les appels en générant des signatures de méthodes basées sur le passage de tableaux d’objets. Si l’on reprends notre exemple précédent nous avons donc l’équivalent suivant:

public void doSomething(String[] values) {
// do something here
}

Et le client:

public void callDoSomething() {
doSomething(new String[0]);
doSomething(new String[]{"a", "b", "c"});
}

Bref les varargs c’est bien, ça simplifie l’écriture de mon code mais… Mais si je ne comprends pas comment ça marche je peux faire des erreurs bête… Et je dirais que même si je comprends comment ça marche je peux louper certains changements relativement facilement.

Prenons un exemple simple. Disons qu’une équipe A est chargée de développer un jar d’utilitaires pour une équipe B.

La première version de l’utilitaire contient dans une des classes la méthode suivante:

public void doSomething() {
// do something here
}

L’équipe B utilise ma méthode avec un appel simple:

public void callDoSomething() {
doSomething();
}

Dans la release suivante l’équipe A ajoute un nouveau paramètre optionnel à l’aide des VarArgs. L’intérêt est évident: les utilisateurs existants n’auront pas à modifier leur code pour continuer d’utiliser l’utilitaire, et les nouveaux utilisateurs peuvent bénéficier des nouvelles options offertes par le nouvel argument optionnel.

public void doSomething(String... params) {
// do something here
}

Mon utilitaire comprends d’autres méthodes et la nouvelle amélioration en plus d’ajouter cette modification améliore le comportement de plusieurs autres de ces outils (sans changement dans l’API). L’équipe B particulièrement intéressée par ces améliorations décide donc de migrer vers la nouvelle version.
Les développeurs des l’équipe B sont des gens consciencieux, ils ont développé leurs tests unitaires, d’intégration etc.. et leur intégration continue fonctionne bien. Sans aucune modification à leur code l’inclusion de ma nouvelle version n’a causé aucun soucis.

L’équipe B décide donc d’inclure mon nouveau jar dans leur environnement de production. Comme leur application est très lourde et n’a pas été modifiée (aucun changement de code) l’équipe décide pour faciliter la manoeuvre de ne mettre à jour que le jar utilitaire.

A l’execution comme vous vous en doutez puisque vous avez bien suivi la réalité des VarArgs l’erreur suivante se produit:

java.lang.NoSuchMethodError: fr.fastconnect.java.blog.varargs.MyProviderClass.doSomething()V
at fr.fastconnect.java.blog.varargs.UsingClass.main(UsingClass.java:10)

Note: dans le contexte de mon projet réel l’inclusion a heureusement été faite sur un environnement de test (je voulais donner un effet « scénaristique » un peu plus dramatique).

Gardez donc en tête, les Varargs ne sont pas une fonctionnalité de runtime mais de compilation, il n’y a pas de magie donc soyez prudents!!

Java : petit quizz #1

Bonjour,

Depuis quelques temps, je propose à la mailing liste (interne) quelques petits Quizz dont la 1ère personne qui a trouvé la bonne réponse a droit à un petit chocolat. Et bien, à partir d’aujourd’hui, nous avons décidé de mettre ces Quizz sur notre blog afin de permettre à d’autres passionnés d’avoir la possibilité de fêter Pâques avant tout le monde :)

Et comme tout évènement/lancement/campagne publicitaire, afin d’attirer le maximum de monde sur notre blog, je ne vais vous proposer qu’une seule question qui est la suivante :

Quelles sont les situations où un thread peut entrer dans l’état « d’attente »  (waiting state) ?

(si possible donner la liste exhaustive)

A vos claviers… chocolat ! :)

 

==== Je remets ci-dessous la réponse du quizz

Effectivement la méthode “Object.wait()” est une des manières pour faire entrer un thread en “waiting state”. Ci-dessous les autres cas possibles :

1. en utilisant la méthode “Thread.sleep()”(sans timeout)
2. en essayant d’acquérir un “lock” (pour la synchronisation) ou LockSupport.park()
3. en attente d’une ressource I/O bloquante
4. en utilisant la méthode “Thread.join()” (sans timeout)

Pour plus d’information, vous pouvez consulter les pages suivantes :

http://download.oracle.com/javase/7/docs/api/java/lang/Thread.State.html#WAITING

http://download.oracle.com/javase/tutorial/essential/concurrency/index.html