Question

J'ai écrit une méthode pour convertir un nombre donné de jours en millisecondes:

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24 * 60 * 60 * 1000;
}

J'ai eu du mal à comprendre ce que je fait de mal. Maintenant, ma question: Est-ce que l'erreur si évidente?

La méthode corrigée:

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = ((long) expireTimeInDays) * 24 * 60 * 60 * 1000;
}

Si je ne convertit pas l'entier de temps avant de calculer, je reçois un mauvais résultat complet.

Était-ce utile?

La solution

est-il évident? Je suppose que cela dépend de combien de temps vous avez utilisé Java et combien de fois vous avez dû faire face à quelques millisecondes. Bien sûr, il devrait être correct jusqu'à environ 24 jours ...

Je pense que le plus grand indice devrait être que renvoie un System.currentTimeMillis() long. C'est une bonne indication qu'un certain nombre de millisecondes peut devenir gros. Le type de la variable que vous définissez devrait être une bonne indication aussi.

Bien sûr, vous avez aussi got savoir que si vous faites des opérations arithmétiques avec ints, le résultat sera avec wrap-int autour de trop-plein. Que c'est suffisamment évidente ou ne pouvait pas être débattue, mais ce serait une discussion assez inutile. En C # si vous avez activé la vérification de débordement, vous auriez trouvé le bug assez rapidement -. Mais pas beaucoup de développeurs le faire (en fait, je ne sais pas si je devrais probablement)

Autres conseils

Oui, il est assez évident si vous l'avez déjà fait. Chaque fois que vous voyez une série de chiffres multiplié sur vous devriez commencer automatiquement penser à des erreurs de débordement d'entier. Dans ce cas, vous êtes prêt à déborder si est plus expireTimeInDays 24. Techniquement, vous devriez penser à des erreurs de débordement chaque fois que vous travaillez avec des entiers , mais la multiplication d'un groupe d'entre eux comme celui-ci devrait être un très grand drapeau rouge.

Votre variable d'opérandes et les numéros littérales sont de type int. Le type de données int a une valeur maximale de 2 ^ 31 -1. Par conséquent, avec un si grand nombre, le type de données d'int déborde conduisant à une apparente réponse incorrecte.

Dans votre premier exemple, l'int n'est promu à une longue affectation à la sur variable qui se produit après le calcul. Le résultat du calcul est un int.

Le second exemple, jette le premier opérande à une longue, ce qui provoque la promotion du calcul à une longue. Dans ce cas, le résultat du calcul est une longue, en raison de la promotion. Le type de données long est plus assez grand pour votre calcul.

Vous pouvez être intéressé de savoir que cela est couvert dans "Java" Puzzlers par Joshua Bloch et Neal Gafter.


(source: javapuzzlers.com )

Vous trouverez de nombreux autres pièges Java, des pièges et des cas de coin dans ce livre.

Je suis d'accord avec le starblue qui a laissé un commentaire. Append un L au nombre.

Non, ce n'est pas évident.

Mais croyez-moi, après quelques années de pratique et la correction des bugs comme cela, vous devenez très sensibles au sujet de débordements d'entier et juste faire la bonne chose, sans même y penser.

Il est quelque chose que tout le monde happend. Sans aucun doute aucun signe de mauvaise pratique de code, l'ignorance ou ainsi.

Il suffit d'ajouter aux autres réponses, je l'ai trouvé utile dans le passé pour définir des constantes (public static final long) tels que ou MILLISECS_DAY MILLISECS_HOUR. Beaucoup plus lisible et utile.

Une autre façon d'écrire c'est

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = (long) expireTimeInDays * 24 * 60 * 60 * 1000;
}

ou

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}

Si vous utilisez FindBugs sur votre code, il détecte ce problème exact. « ICAST: Résultat de la multiplication entier converti en long. » L'exemple de FindBugs est exactement ce que vous faites; calcul des jours en millisecondes.

Ce problème n'a pas été évident pour moi la première fois que je suis tombé sur elle.

Il y a un certain outil d'analyse statique (findbugs) qui trouveront ce type d'erreurs.

mathématiques numérique sur les ordinateurs peut être difficile. Pour des questions de fonctionnement peut affecter la précision et la précision de manière que vous ne penserez pas. mathématiques Date peut également être étonnamment difficile. Souvent, il est préférable d'utiliser les routines Date / Calendrier plutôt que d'essayer de faire le calcul vous-même, mais ces routines ne sont pas les meilleurs conçus dans la bibliothèque de classes java.

Je ne cherche pas à justifier mon erreur, mais ce serait bien si le compilateur Java a été assez intelligent pour promouvoir l'int à un bien avant le calcul (une fois le calcul est affecté à une variable de type long)

Par ailleurs, je l'habitude de travailler avec C / C ++ et si elle était un programme C, j'eu le même problème, mais avec ce genre d'opération il y a quelques années, j'avais été plus prudent.

Je paierai plus d'attention la prochaine fois (ou passer en python) ...: D

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top