Domanda

Ho scritto un metodo per convertire un determinato numero di giorni di millisecondi:

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

Ho avuto un momento difficile capire cosa ho sbagliato.Ora la mia domanda:È che l'errore così evidente ?

Il corretto metodo:

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

Se non riesco a convertire il numero intero a lungo prima di calcolare, io ottenere un risultato sbagliato.

È stato utile?

Soluzione

E 'ovvio? Immagino che dipende da quanto tempo hai usato Java e quante volte hai avuto a che fare con millisecondi. Naturalmente, dovrebbe essere a posto per un massimo di circa 24 giorni ...

Credo che il più grande suggerimento dovrebbe essere che System.currentTimeMillis() restituisce un long. Questa è una buona indicazione che un certo numero di millisecondi può ottenere grandi. Il tipo di variabile che si sta impostando dovrebbe essere un buon indizio troppo.

Naturalmente, hai anche avuto modo di sapere che se si fa operazioni aritmetiche con interi, il risultato sarà int con wrap-around in caso di overflow. Se questo è sufficientemente evidenti o non poteva essere messa in discussione, ma sarebbe una discussione abbastanza inutile. In C # Se si è attivato troppo pieno controllo su, avresti trovato il bug abbastanza rapidamente -. Ma poi non molti sviluppatori farlo (anzi, lo faccio anche se probabilmente non dovrei)

Altri suggerimenti

Sì, è abbastanza evidente se hai fatto prima. Ogni volta che vedi una stringa di numeri moltiplicato fuori si dovrebbe cominciare a pensare automaticamente errori di overflow interi. In questo caso si sta insieme a traboccare se expireTimeInDays è più di 24. Tecnicamente si dovrebbe pensare a errori di overflow ogni volta che si lavora con numeri interi , ma moltiplicando un gruppo di loro come questo dovrebbe essere una grande bandiera rossa.

La variabile operando ei numeri letterali sono di tipo int. Il tipo di dati int ha un valore massimo di 2 ^ 31 -1. Quindi con così gran numero, il tipo di dati di int overflow che porta ad una risposta sbagliata apparente.

Nel vostro primo esempio, l'int è promosso solo per un lungo in missione alla variabile che si verifica dopo il calcolo. Il risultato del calcolo è un int.

Il secondo esempio, lancia il primo operando ad una lunga, causando la promozione del calcolo per un lungo. In questo caso, il risultato del calcolo è un lungo, a causa di promozione. Il tipo di tempo i dati è più che abbastanza grande per il calcolo.

Si può essere interessati a sapere che è coperto in "Java Puzzle" di Joshua Bloch e Neal Gafter.

alt text
(fonte: javapuzzlers.com)

Troverete molte altre Java insidie, trappole e angolo casi in cui il libro.

Sono d'accordo con il starblue che hanno lasciato un commento.Aggiungere una L per il numero.

No, non è ovvio.

Ma credimi, dopo alcuni più anni di pratica e bug di fissaggio come questo si diventa molto sensibile circa integer overflow e basta fare la cosa giusta, senza nemmeno pensarci.

E 'qualcosa che successo a tutti. Sicuramente nessun segno di pratica codice male, l'ignoranza o giù di lì.

Giusto per aggiungere alle altre risposte, ho trovato utile in passato per definire le costanti (public static final long), come MILLISECS_DAY o MILLISECS_HOUR. Molto più leggibile e utile.

Un altro modo di scrivere questo è

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

o

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

Se si utilizza FindBugs sul vostro codice è in grado di rilevare questo problema esatto. "ICAST: Risultato della moltiplicazione intero cast a lungo." esempio FindBugs' è esattamente quello che stai facendo; calcolare i giorni in millisecondi.

Questo problema non era ovvio per me la prima volta che mi sono imbattuto in esso.

Ci sono alcuni tool di analisi statica (findbugs) che troveranno questo tipo di errori.

matematica numerico su computer può essere difficile. Ordine di questioni di funzionamento può influenzare la precisione e l'accuratezza in modi che non ti aspetti. Data la matematica può anche essere sorprendentemente difficile. Spesso è meglio usare le routine Data / Calendario piuttosto che cercare di fare i calcoli da soli, ma quelle routine non sono i migliori progettati nella libreria di classi Java.

Non sto cercando di giustificare il mio errore, ma sarebbe bello se il compilatore Java è stato abbastanza intelligente per promuovere l'int a una lunga prima del calcolo (una volta che il calcolo viene assegnato a una variabile di tipo long)

A proposito, ho usato per lavorare con C / C ++ e se si trattava di un programma C, avrei avuto lo stesso problema, ma qualche anno fa sarei stato più attento a questo tipo di operazione.

Pagherò più attenzione la prossima volta (o passare a python) ...: D

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top