Aperiquiz #4 : Integer equals Integer

Soit le code suivant :


Quel est la valeur de c ?
  • true
  • false
  • Erreur de compilation
  • Une exception est levée lors de l'exécution
Réponse : (cliquez pour afficher)

Permalink  |  Commentaires (5)

Types primitifs : pièges courants

It's a trap

Je viens de tomber dans la soirée sur deux pièges, non triviaux, mais facile à éviter pour peu de les connaître...

27/10 != 2.7

Le premier bout de code ressemblait à celui-ci :
public class Main {

    public static void main(String... args) {
        float price = 27/10;
        System.out.println("Price: " + price);
    }

}

Alors qu'il est facile de penser que le code suivant va afficher "Price: 2.70" lors de l'exécution, la réalité est tout autre. Effectivement, le résultat une fois ce code compilé / exécuté est "Price: 2.00".

Le piège est le suivant :
  • 27 est, en Java, un entier
  • 10 est, toujours en Java, un entier
  • L'opération 27/10 est la division de deux entiers. Pour la JVM, le résultat est donc un entier. Donc 2.
  • La valeur 2 est assignée à une variagle de type float, la valeur 2 est transformée en 2.00
  • La valeur 2.00 est affichée dans la console.

Il est facile de contourner ce problème : transformer notre division d'entier en division de nombre flottants :
public class Main {

    public static void main(String... args) {
        float price = 27.0/10.0;
        System.out.println("Price: " + price);
    }

}

Dans ce bloc de code, 27.0 et 10.0 sont des nombres à virgule flottante. La division des deux donne une nombre à virgule flottante, donc 2.7. Et le résultat est donc celui attendu.

return (int) 2.7 - 2.4;

Le second bloc de code piégé consistait à comparer deux entiers :
public class FloatComparator implements ComparatoréFloat> {

    public int compare(Float f1, Float f2) {
        return (int) (f2 - f1);
    }

}

A première vue, ce code semble lui aussi entièrement correct. Le raisonnement suivi est celui-ci :
  • Si je renvoie le résultat de f2 - f1, mon objet triera des nombres par ordre croissant
  • La méthode compare doit renvoyer un entier
  • Je caste le résultat de ma soustraction (un float) en int.

Ce code fonctionne presque tout le temps. Le problème tiens dans le presque... Pour comprendre où est le problème, rien ne vaut une simulation :
  • Je souhaite comparer 2.7 et 2.8
  • 2.8 - 2.7 renvoie 0.1, un nombre positif, donc je respecte le contrat de la méthode compare
  • 0.1 est casté en int, le résultat est 0 alors que f2 est suppérieur a f1, je ne respecte plus le contrat de ma méthode

L'erreur se trouve dans le cast. Il faut donc effectuer un changement dans notre méthode pour renvoyer un nombre positif dans tous les cas où f2 est suppérieur à f1. Par exemple :
public class FloatComparator implements ComparatoréFloat> {

    public int compare(Float f1, Float f2) {
        if (f2 > f1) {
            return 1;
        }
        if (f1 < f2) {
            return -1;
        }
        return 0;
    }

}
Le contrat de Comparator est maintenant respecté.

Permalink  |  Commentaires (0)