W3docs

Numeri in Java

Lavora con i tipi numerici in Java — int, long, float, double — e comprendi precisione, overflow e la classe Number.

Java distingue i numeri interi da quelli in virgola mobile e, all'interno di ciascuna famiglia, offre diverse dimensioni. Scegliere il tipo corretto è importante sia per la correttezza (precisione, intervallo) sia per le prestazioni. Questo capitolo è una guida focalizzata sui tipi numerici, i loro letterali, le conversioni e le insidie che sorprendono i principianti. Si presuppone che tu sappia già come dichiarare una variabile e abbia già visto l'insieme completo dei tipi di dati primitivi.

I tipi primitivi numerici

TipoBitIntervalloStile letterale predefinito
byte8da -128 a 127byte b = 10;
short16da -32.768 a 32.767short s = 30_000;
int32da -2³¹ a 2³¹-1 (≈ ±2,1 miliardi)int i = 1_000_000;
long64da -2⁶³ a 2⁶³-1long l = 9_000L;
float32IEEE 754 singola precisione (~7 cifre)float f = 3.14f;
double64IEEE 754 doppia precisione (~16 cifre)double d = 3.14;

Nel Java di tutti i giorni:

  • Usa int per contatori, indici e la maggior parte dei valori interi.
  • Usa long quando potresti superare ~2 miliardi (dimensioni di file, millisecondi dall'epoch, generatori di ID).
  • Usa double per i calcoli in virgola mobile.
  • Usa float solo quando la memoria è scarsa o un'API lo richiede.

Letterali interi

Le cifre semplici sono int:

int answer = 42;
int million = 1_000_000;     // underscores are ignored

Suffisso L (maiuscolo preferito) per long:

long big = 9_000_000_000L;

Prefisso 0x per esadecimale, 0b per binario, 0 per ottale:

int hex = 0xFF;        // 255
int bin = 0b1010;      // 10
int oct = 0755;        // 493 — be careful, easy to write by accident

(I letterali ottali sono una fonte frequente di bug — 0123 non è 123, è 83. Evita gli zeri iniziali a meno che tu non voglia davvero indicare un valore ottale.)

Letterali in virgola mobile

I decimali semplici sono double:

double pi = 3.14159;
double e = 2.71828;

Suffisso f per float, d per double esplicito (facoltativo):

float pif = 3.14f;
double pid = 3.14d;

La notazione scientifica funziona:

double avogadro = 6.022e23;
double tiny = 1.0e-9;

Conversione tra tipi numerici

Java esegue automaticamente una conversione widening quando un tipo più piccolo confluisce in uno più grande (non si può perdere nessun dato):

int x = 7;
double promoted = x;   // 7.0 — int widens to double automatically

Il percorso inverso è il narrowing: il valore potrebbe non entrare, quindi Java ti obbliga a scrivere un cast esplicito e scarta silenziosamente ciò che non ci sta. Si tratta di troncamento, non di arrotondamento:

double d = 9.99;
int i = (int) d;       // 9 — the fraction is dropped, never rounded

long big = 9_000_000_000L;
int truncated = (int) big;   // 410065408 — high bits lost, value is garbage

Per questo motivo, restringi il tipo solo quando sei certo che il valore ci stia. Per arrotondare un double all'intero più vicino invece di troncare, usa Math.round (vedi Java Math).

Le conversioni avvengono anche all'interno delle espressioni. La divisione intera scarta il resto, il che sorprende i principianti:

System.out.println(7 / 2);     // 3   — both operands are int, so int division
System.out.println(7 / 2.0);   // 3.5 — one double operand promotes the whole expression

Per le regole complete sui cast espliciti, consulta Java Type Casting.

Overflow

L'aritmetica intera va in wrap silenziosamente oltre i limiti del tipo. Non viene lanciata alcuna eccezione:

int max = Integer.MAX_VALUE;
System.out.println(max + 1);   // -2147483648 (Integer.MIN_VALUE)

Per l'aritmetica con controllo dell'overflow, usa la famiglia Math.exact:

Math.addExact(Integer.MAX_VALUE, 1);   // throws ArithmeticException
Math.multiplyExact(100_000, 100_000);  // throws too

Utile quando la correttezza è più importante delle prestazioni — calcoli finanziari, dimensioni di allocazione, ecc.

Precisione in virgola mobile

double e float seguono lo standard IEEE 754 binario — non possono rappresentare la maggior parte delle frazioni decimali in modo esatto:

System.out.println(0.1 + 0.2);   // 0.30000000000000004

Non confrontare mai i valori in virgola mobile con ==. Confronta entro una tolleranza:

double diff = Math.abs(a - b);
if (diff < 1e-9) { /* close enough */ }

Per importi di denaro o in qualsiasi caso tu abbia bisogno di aritmetica decimale esatta, usa BigDecimal:

import java.math.BigDecimal;

BigDecimal sum = new BigDecimal("0.1").add(new BigDecimal("0.2"));
System.out.println(sum);   // 0.3

Passa sempre stringhe a new BigDecimal(...). Il costruttore con double reintrodurrebbe l'imprecisione binaria.

Valori speciali in virgola mobile

double ha tre valori che non sono numeri ordinari:

double posInf = Double.POSITIVE_INFINITY;
double negInf = Double.NEGATIVE_INFINITY;
double nan = Double.NaN;

System.out.println(1.0 / 0);          // Infinity
System.out.println(-1.0 / 0);         // -Infinity
System.out.println(0.0 / 0);          // NaN

System.out.println(nan == nan);       // false — NaN compares unequal to everything
System.out.println(Double.isNaN(nan)); // true

Usa Double.isNaN(x) per verificare il NaN; == non funzionerà.

Le classi wrapper

Ogni tipo primitivo ha una classe wrapper corrispondente: Byte, Short, Integer, Long, Float, Double. Le wrapper estendono la classe astratta Number. Sono necessarie quando:

  • Si usano collezioni che contengono oggetti: List<Integer>, Map<String, Double>.
  • Si effettua il parsing da stringhe: Integer.parseInt("42"), Double.parseDouble("3.14").
  • Si converte in un tipo numerico diverso tramite .intValue(), .doubleValue(), ecc.

Java esegue l'autoboxing tra primitivo e wrapper automaticamente:

List<Integer> ids = new ArrayList<>();
ids.add(42);            // autobox: int → Integer
int first = ids.get(0); // unbox: Integer → int

BigInteger e BigDecimal

Quando i numeri possono essere più grandi di long o hai bisogno di precisione decimale:

import java.math.BigInteger;

BigInteger huge = new BigInteger("123456789012345678901234567890");
huge.multiply(huge);

BigDecimal price = new BigDecimal("19.95");
BigDecimal tax = price.multiply(new BigDecimal("0.07"));

Sono più lenti dei tipi primitivi, ma per i casi che li richiedono è il compromesso giusto.

Una dimostrazione

java— editable, runs on the server

Cosa c'è dopo

  • Java MathMath.abs, Math.round, Math.pow e il resto del toolkit numerico.
  • Java Operators — come si comportano gli operatori aritmetici, di confronto e bit a bit su questi tipi.
  • Java Booleans — il tipo a due valori di Java, con molti meno dettagli.

Esercitazione

Pratica
Quale tipo è più appropriato per un importo di denaro in Java?
Quale tipo è più appropriato per un importo di denaro in Java?
Was this page helpful?