Java Numbers
Work with numeric types in Java — int, long, float, double — and understand precision, overflow, and the Number class.
Java distinguishes integer and floating-point numbers, and within each family it has several sizes. Picking the right type matters for both correctness (precision, range) and performance. This chapter is a focused walkthrough of the numeric types, their literals, and the gotchas that catch beginners.
The numeric primitives
| Type | Bits | Range | Default literal style |
|---|---|---|---|
byte | 8 | -128 to 127 | byte b = 10; |
short | 16 | -32,768 to 32,767 | short s = 30_000; |
int | 32 | -2³¹ to 2³¹-1 (≈ ±2.1 billion) | int i = 1_000_000; |
long | 64 | -2⁶³ to 2⁶³-1 | long l = 9_000L; |
float | 32 | IEEE 754 single precision (~7 digits) | float f = 3.14f; |
double | 64 | IEEE 754 double precision (~16 digits) | double d = 3.14; |
In everyday Java:
- Use
intfor counters, indexes, and most integer values. - Use
longwhen you might exceed ~2 billion (file sizes, milliseconds since epoch, ID generators). - Use
doublefor floating-point math. - Use
floatonly when memory is tight or an API requires it.
Integer literals
Plain digits are int:
int answer = 42;
int million = 1_000_000; // underscores are ignoredSuffix L (uppercase preferred) for long:
long big = 9_000_000_000L;Prefix 0x for hex, 0b for binary, 0 for octal:
int hex = 0xFF; // 255
int bin = 0b1010; // 10
int oct = 0755; // 493 — be careful, easy to write by accident(Octal literals are a frequent source of bugs — 0123 is not 123, it's 83. Avoid leading zeros unless you really mean octal.)
Floating-point literals
Plain decimals are double:
double pi = 3.14159;
double e = 2.71828;Suffix f for float, d for explicit double (optional):
float pif = 3.14f;
double pid = 3.14d;Scientific notation works:
double avogadro = 6.022e23;
double tiny = 1.0e-9;Overflow
Integer arithmetic wraps silently around the type's bounds. No exception is thrown:
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648 (Integer.MIN_VALUE)For overflow-checked arithmetic, use the Math.exact family:
Math.addExact(Integer.MAX_VALUE, 1); // throws ArithmeticException
Math.multiplyExact(100_000, 100_000); // throws tooUseful when correctness matters more than performance — financial calculations, allocation sizes, etc.
Floating-point precision
double and float are IEEE 754 binary — they cannot represent most decimal fractions exactly:
System.out.println(0.1 + 0.2); // 0.30000000000000004Never compare floating-point values with ==. Compare within a tolerance:
double diff = Math.abs(a - b);
if (diff < 1e-9) { /* close enough */ }For amounts of money or anywhere you need exact decimal arithmetic, use BigDecimal:
import java.math.BigDecimal;
BigDecimal sum = new BigDecimal("0.1").add(new BigDecimal("0.2"));
System.out.println(sum); // 0.3Always pass strings to new BigDecimal(...). The double constructor would re-introduce the binary inexactness.
Special floating-point values
double has three values that aren't ordinary numbers:
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)); // trueUse Double.isNaN(x) to test for NaN; == won't work.
The wrapper classes
Each primitive has a matching wrapper: Byte, Short, Integer, Long, Float, Double. The wrappers extend the abstract Number class. You need them when:
- Using collections that hold objects:
List<Integer>,Map<String, Double>. - Parsing from strings:
Integer.parseInt("42"),Double.parseDouble("3.14"). - Converting to a different numeric type via
.intValue(),.doubleValue(), etc.
Java autoboxes between primitive and wrapper automatically:
List<Integer> ids = new ArrayList<>();
ids.add(42); // autobox: int → Integer
int first = ids.get(0); // unbox: Integer → intBigInteger and BigDecimal
When numbers can be larger than long or you need decimal precision:
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"));They're slower than primitives, but for the cases that need them, that's the right trade-off.
A demonstration
What's next
Java Booleans — Java's two-valued type, in much less detail.
Practice
Which type is most appropriate for an amount of money in Java?