double
In short: A primitive data type for floating-point numbers (numbers with decimal places) with double precision (64 bits).
In more detail: double is the default type for decimal numbers in Java — literals like 3.14 are automatically interpreted as double with no further suffix (the smaller float type needs an f suffix: 3.14f). Because of the binary floating-point representation, exact comparisons with == are risky (rounding errors); for monetary amounts, BigDecimal is the safer choice.
In Depth
double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 0.30000000000000004 - NOT 0.3!
System.out.println(a + b == 0.3); // false - classic rounding-error bug
// Safer comparison with tolerance instead of exact ==
double epsilon = 0.0000001;
boolean closeEnough = Math.abs((a + b) - 0.3) < epsilon; // true
// For monetary amounts: BigDecimal instead of double
BigDecimal price = new BigDecimal("19.99");
BigDecimal tax = price.multiply(new BigDecimal("0.19"));The reason for 0.1 + 0.2 != 0.3: double stores numbers in binary (powers of two), and many numbers that are “neat” in the decimal system, like 0.1, can’t be represented exactly in binary — similar to how 1/3 can’t be written exactly as a finite decimal number. For the vast majority of calculations (physics, graphics, measurements) this tiny inaccuracy is irrelevant, but for monetary amounts it’s unacceptable — there, practically every style guide requires BigDecimal, which guarantees exact decimal arithmetic with no rounding errors (but is slower for it and doesn’t support natural operators like +/*, only method calls like .add()/.multiply()).
double vs. float — which one when?
double (64 bits, ~15-17 significant decimal digits) is the default type in Java; float (32 bits, ~6-9 significant digits) needs less memory but is less precise. In practice, float is used almost only where memory/performance for huge amounts of data is critical (e.g. 3D graphics engines, machine learning arrays with millions of values) — for normal application code, double is almost always the right choice, if only because Java literals with no suffix are automatically double and you’d otherwise have to constantly append f.
Special values: Infinity and NaN
Unlike int, where division by zero throws an ArithmeticException, double has defined special values for “impossible” results:
double infinity = 1.0 / 0.0; // Infinity, NO exception
double negInfinity = -1.0 / 0.0; // -Infinity
double notANumber = 0.0 / 0.0; // NaN ("Not a Number")
System.out.println(notANumber == notANumber); // false! NaN is never equal to anything, not even itself
System.out.println(Double.isNaN(notANumber)); // true - the correct way to check for NaNThese IEEE 754 special values (the international standard that double/float implement) are a common debugging pitfall: a NaN that unnoticed propagates through a calculation chain makes EVERY comparison with it false at the end — including == comparisons with itself, which is why Double.isNaN() instead of == Double.NaN is the only correct test.
See also: Type Casting, Non-primitive Types, byte