W3docs

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

TypeBitsRangeDefault literal style
byte8-128 to 127byte b = 10;
short16-32,768 to 32,767short s = 30_000;
int32-2³¹ to 2³¹-1 (≈ ±2.1 billion)int i = 1_000_000;
long64-2⁶³ to 2⁶³-1long l = 9_000L;
float32IEEE 754 single precision (~7 digits)float f = 3.14f;
double64IEEE 754 double precision (~16 digits)double d = 3.14;

In everyday Java:

  • Use int for counters, indexes, and most integer values.
  • Use long when you might exceed ~2 billion (file sizes, milliseconds since epoch, ID generators).
  • Use double for floating-point math.
  • Use float only 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 ignored

Suffix 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 too

Useful 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.30000000000000004

Never 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.3

Always 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)); // true

Use 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 → int

BigInteger 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

java— editable, runs on the server

What's next

Java Booleans — Java's two-valued type, in much less detail.

Practice

Practice

Which type is most appropriate for an amount of money in Java?