double
Kurz: Ein primitiver Datentyp für Gleitkommazahlen (Zahlen mit Nachkommastellen) mit doppelter Genauigkeit (64 Bit).
Genauer: double ist in Java der Standard-Typ für Kommazahlen — Literale wie 3.14 werden ohne weiteren Suffix automatisch als double interpretiert (für den kleineren float-Typ braucht es ein f-Suffix: 3.14f). Wegen der binären Gleitkommadarstellung sind exakte Vergleiche mit == riskant (Rundungsfehler); für Geldbeträge ist BigDecimal die sicherere Wahl.
Im Detail
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 0.30000000000000004 - NICHT 0.3!
System.out.println(a + b == 0.3); // false - klassischer Rundungsfehler-Bug
// Sicherer Vergleich mit Toleranz statt exaktem ==
double epsilon = 0.0000001;
boolean nahGenug = Math.abs((a + b) - 0.3) < epsilon; // true
// Für Geldbeträge: BigDecimal statt double
BigDecimal preis = new BigDecimal("19.99");
BigDecimal steuer = preis.multiply(new BigDecimal("0.19"));Der Grund für 0.1 + 0.2 != 0.3: double speichert Zahlen binär (Zweierpotenzen), und viele im Dezimalsystem “glatte” Zahlen wie 0.1 lassen sich binär nicht exakt darstellen — ähnlich wie sich 1/3 dezimal nicht exakt als endliche Zahl schreiben lässt. Für die allermeisten Berechnungen (Physik, Grafik, Messwerte) ist diese winzige Ungenauigkeit irrelevant, bei Geldbeträgen dagegen inakzeptabel — dort verlangt praktisch jeder Styleguide BigDecimal, das exakte Dezimalarithmetik ohne Rundungsfehler garantiert (dafür aber langsamer ist und keine natürlichen Operatoren wie +/* unterstützt, sondern Methodenaufrufe wie .add()/.multiply()).
double vs. float — wann welcher?
double (64 Bit, ~15-17 signifikante Dezimalstellen) ist in Java der Standardtyp; float (32 Bit, ~6-9 signifikante Stellen) benötigt weniger Speicher, ist aber ungenauer. In der Praxis wird float fast nur noch dort eingesetzt, wo Speicherplatz/Performance bei riesigen Datenmengen kritisch ist (z. B. 3D-Grafik-Engines, Machine-Learning-Arrays mit Millionen Werten) — für normalen Anwendungscode ist double fast immer die richtige Wahl, schon weil Java-Literale ohne Suffix automatisch double sind und man sonst ständig f anhängen müsste.
Spezialwerte: Infinity und NaN
Anders als int, wo eine Division durch Null eine ArithmeticException wirft, kennt double definierte Spezialwerte für “unmögliche” Ergebnisse:
double unendlich = 1.0 / 0.0; // Infinity, KEINE Exception
double negUnendlich = -1.0 / 0.0; // -Infinity
double keineZahl = 0.0 / 0.0; // NaN ("Not a Number")
System.out.println(keineZahl == keineZahl); // false! NaN ist nie gleich irgendetwas, auch nicht sich selbst
System.out.println(Double.isNaN(keineZahl)); // true - der korrekte Weg, auf NaN zu prüfenDiese IEEE-754-Spezialwerte (der internationale Standard, den double/float implementieren) sind ein häufiger Debugging-Stolperstein: ein NaN, das sich unbemerkt durch eine Berechnungskette zieht, macht am Ende JEDEN Vergleich damit zu false — inklusive ==-Vergleiche mit sich selbst, weshalb Double.isNaN() statt == Double.NaN der einzig korrekte Test ist.
Siehe auch: Type Casting, Non-primitive Types, byte