Archives mensuelles : novembre 2010

La solution pour « faire pleurer vos collègues »

Après quelques jours d’attente, je me lance et vous propose une solution.

La question était posée ici

Pour rappel il fallait dire ce que fait le code suivant :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test  
public void testCalcul1() {  
  int i;  
  i = i++;  
  System.out.println(i);  
}  
 
@Test  
public void testCalcul2() {  
  int i = 0;  
  i = i++;  
  System.out.println(i);  
}  
 
@Test  
public void testCalcul3() {  
  int i = 1;  
  i = 1 + i++;  
  System.out.println(i);  
}  
 
@Test  
public void testCalcul4() {  
  int i = 1;  
  i = 1 + ++i + i++;  
  System.out.println(i);  
}

Commençons par la méthode « testCalcul1″. Elle ne compile tout simplement pas puisque la variable « i » n’a pas été initialisée explicitement. Contrairement aux variables de classes qui sont auto initialisées (warning compilation incomplète) avec les valeurs par défaut (zéro pour un int), les variables de méthodes doivent être explicitement initialisées avant de pouvoir être utilisées. On a néanmoins le droit de ne pas initialiser une variable sous resserve de ne pas l’utiliser. Du coup elle ne sert à rien…

La méthode « testCalcul2″ écrit « 0 » (zéro). Instinctivement on se doute bien que ça allait écrire soit 0 soit 1. Ici la clé de l’énigme est l’ordre de priorité du « = » et du « ++ ». Pour nous aider à bien comprendre, créons la méthode suivante.

1
2
3
4
5
6
7
8
9
10
11
@Test  
public void testCalcul2b() {  
  int i = 0;
  int j = 0;
  j = i++;  
  System.out.println("i=" + i);  
  System.out.println("j=" + j);  
}  
 
// --> i=1
// --> j=0

On voit bien, grace à l’instruction « j = i++ » que l’opérateur d’affectation « = » est prioritaire à la post-incrémentation « ++ ». Du coup, si on revient à « testCalcul2″, la variable « i » va donc prendre la valeur « 0 ». Mais me direz-vous, que devient le « ++ » mis en attente ? Et ben il est effectivement réalisé, mais sur une autre variable « i » qui, pour le coup, est perdue même si elle reste présente en mémoire.

La méthode « testCalcul3″ écrit « 2 ». C’est le même raisonnement que pour « testCalcul2″ mais avec des conditions initiales légèrement différentes.

Quant à « testCalcul4″, elle écrit « 5 ». Je l’ai programmer pour rigoler au départ et, finalement, je me suis rendu compte qu’elle était intéressante, pas seulement pour avoir une écriture super complexe mais aussi pour bien voir les priorités. Pour la comprendre, on peut commencer par la simplifier comme suit.

1
2
3
4
5
6
7
8
@Test  
public void testCalcul4b() {  
  int i = 1;  
  i = 1 + ++i ;  
  System.out.println(i);  
}
 
// --> 3

En fait le « ++i » passe en premier, du coup « i = 1 + ++i » est équivalent à « i = 1 + 2″, donc « i » vaut « 3 » à la fin. Et pour la même raison, l’instruction « i = 1 + ++i + i++ » revient à « i = 1 + 2 + 2++ » or comme vu dans « testCalcul2″, le « ++ » va passer après le « = » et donc on obtient seulement « 1 + 2 + 2 = 5″…

CQFD… Bonne partie de casse-tête !

Faire pleurer vos collègues

Voici 4 méthodes. Pour chacune il faut expliquer ce qui se passe, sans tester le code (sinon c’est trop facile).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test
public void testCalcul1() {
    int i;
    i = i++;
    System.out.println(i);
}
 
@Test
public void testCalcul2() {
    int i = 0;
    i = i++;
    System.out.println(i);
}
 
@Test
public void testCalcul3() {
    int i = 1;
    i = 1 + i++;
    System.out.println(i);
}
 
@Test
public void testCalcul4() {
    int i = 1;
    i = 1 + ++i + i++;
    System.out.println(i);
}

Serializable et UID

Voici une petite précision qui n’a l’air de rien mais qui a son importance.

Quand vous avez une classe qui implémente l’interface Serializable, pensez à créer l’attribut « serialVersionUID« .

En général Eclipse vous invite à le faire et vous propose de le générer automatiquement (ne prenez pas la valeur bidon) via le quick fix.

Je vous renvoie vers le Javadoc : http://download.oracle.com/javase/1.5.0/docs/api/java/io/Serializable.html
Lire la suite

Sortie rapide des boucles

Je vous invite à programmer vos boucles, et plus spécifiquement vos conditions de test, pour sortir au plus vite des boucles.

Par exemple, dans le cas suivant :

1
2
3
4
5
6
7
boolean ok = false ;
for(Foo foo : foos) {
  if( foo.truc() ) {
     ok = true ;
  }
}
return ok ;

Dans ce genre de cas, pensez à mettre un « break » dans votre boucle, pour ne pas continuer à parcourir inutilement la liste, puisque la valeur est calculée et ne changera plus.

Lire la suite

Enum.valueOf

Voici un point rapide sur les enums et plus spécifiquement sur les méthodes valueOf et values.

Partons d’une enum simple :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum AnimalEnum {
 
    CHIEN("Wouaf"),  
    CHAT("Miaou"),  
    VACHE("Meuh"),  
    SERPENT("Kss");
 
    final private String onomatopee;
 
    AnimalEnum(String onomatopee) {
         this.onomatopee = onomatopee;
    }
 
    public String getOnomatopee() {
         return onomatopee;
    }
}

Vous noterez bien au passage que l’attribut « onomatopee » a été déclaré final et que ce n’est pas une erreur, à condition qu’il ne soit affecté que dans un seul constructeur.
Lire la suite

Des itérators et des boucles

Nos open-spaces sont souvent lieux de discussion à propos des parcours de liste, notamment lorsqu’on ne dispose que de l’itérator sur la liste comme c’est parfois le cas dans certaines lib.

Pour illustrer tout ça, prenons en compte la liste d’amis, définie de la manière suivante dans un test (version simplifiée).

1
2
3
4
5
6
7
8
9
10
11
private List<string> amis;
 
@Before
public void doBefore() {
    amis = newArrayList(); // cf. tuto Google-Collections
    amis.add("Lucie");
    amis.add("Jean");
    amis.add("Paul");
    amis.add("Marion");
    amis.add("Thierry");
}</string>

Lire la suite