Number Types

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 104 of 133

Java offers several ways to represent numbers, each with a different range, precision, memory cost, and speed. There are six primitive numeric types, a wrapper class for each, the abstract class Number that ties the wrappers together, and two arbitrary-precision classes, BigInteger and BigDecimal, for values that do not fit or must be exact. This lesson maps out the whole family so you can choose the right type for each kind of data. The following lessons examine Integer, Float, Double, BigInteger, and BigDecimal individually.

The Numeric Type Family

Primitive types            Wrapper classes (objects)
  byte    (8-bit)    ─►      Byte      ┐
  short   (16-bit)   ─►      Short     │
  int     (32-bit)   ─►      Integer   │
  long    (64-bit)   ─►      Long      ├─ all extend java.lang.Number
  float   (32-bit)   ─►      Float     │
  double  (64-bit)   ─►      Double    │
                             BigInteger│  (arbitrary-size integers)
                             BigDecimal┘  (exact decimals)

(char is also a 16-bit unsigned integer type internally, but it represents characters and is not a subclass of Number.)

Integer Types

Integer types store whole numbers exactly, as long as the value fits in their range.

TypeBitsMinimumMaximumLiteral
byte8−128127(byte) 10
short16−32,76832,767(short) 10
int32−2,147,483,6482,147,483,64710
long64about −9.22 × 10¹⁸about 9.22 × 10¹⁸10L

All are signed, stored in two's complement. Each wrapper class exposes the limits as constants (Integer.MIN_VALUE, Long.MAX_VALUE), and SIZE and BYTES give the size in bits and bytes.

Arithmetic that exceeds the range wraps around silently:

System.out.println(Integer.MAX_VALUE + 1);      // -2147483648
System.out.println(Long.MAX_VALUE + 1);         // -9223372036854775808

Math.addExact, multiplyExact, and toIntExact throw ArithmeticException instead of wrapping, and BigInteger removes the limit entirely.

Unsigned operations

Java has no unsigned integer types, but the wrapper classes provide methods that treat the bits as unsigned, useful for binary file formats, network protocols, and hash values:

Integer.toUnsignedString(-1);          // "4294967295"
Byte.toUnsignedInt((byte) 200);        // 200 (a byte cast from 200 holds -56)
Integer.divideUnsigned(-2, 2);         // 2147483647

Floating-Point Types

Floating-point types store numbers with a fractional part using the IEEE 754 binary format.

TypeBitsApprox. significant digitsLargest valueSmallest positive valueLiteral
float326–73.4 × 10³⁸1.4 × 10⁻⁴⁵3.14f
double6415–161.8 × 10³⁰⁸4.9 × 10⁻³²⁴3.14

Two points surprise many developers:

  • Float.MIN_VALUE and Double.MIN_VALUE are the smallest positive values, not the most negative ones. The most negative double is -Double.MAX_VALUE.
  • Most decimal fractions are approximations. 0.1 has no exact binary representation, so 0.1 + 0.2 is 0.30000000000000004 as a double. The error is tiny, but it accumulates and breaks equality checks.

Floating-point types also have special values: Infinity, -Infinity, and NaN (not a number), produced by operations such as 1.0 / 0 and 0.0 / 0.

double is the default and the right choice for scientific, statistical, geometric, and graphics calculations. float halves the memory and is used for very large arrays, graphics APIs, and machine-learning data where 7 digits of precision suffice.

Arbitrary-Precision Types

ClassRepresentsUse when
BigIntegerIntegers of any sizeValues beyond long: cryptography, factorials, very large IDs or counters
BigDecimalDecimal numbers with exact digits and controlled roundingMoney, tax, interest, and any calculation that must match decimal arithmetic exactly
new BigDecimal("0.1").add(new BigDecimal("0.2"));   // 0.3 exactly
new BigInteger("2").pow(100);                       // 1267650600228229401496703205376

They are immutable objects, considerably slower than primitives, and use method calls instead of operators (add, multiply, compareTo). Both have their own lessons.

Primitives Versus Wrappers

Primitive (int)Wrapper (Integer)
What it isA raw valueAn object containing a value
Can be nullNoYes
Usable in collections and genericsNoYes (List<Integer>)
Memory4 bytesAbout 16 bytes per object, plus the reference
Comparing with ==Compares valuesCompares object identity
Utility methodsNoparseInt, toBinaryString, compare, constants

Java converts between them automatically (autoboxing and unboxing), which is convenient but has pitfalls: unboxing null throws NullPointerException, and == between two wrapper objects compares references. The Integer Class lesson covers these in detail.

Use primitives for local variables, fields, and arithmetic. Use wrappers where an object is required (collections, generics, nullable database columns).

The Number Class

All wrappers, plus BigInteger and BigDecimal, extend the abstract class java.lang.Number, which defines conversion methods:

MethodReturns
intValue()The value as an int
longValue()The value as a long
doubleValue()The value as a double
floatValue(), shortValue(), byteValue()The value in those types

These conversions can lose information silently: truncating fractions, wrapping values that do not fit, or rounding to fewer significant digits. Code that accepts any Number is convenient (a chart that plots any numeric series, for example), but it should be aware of what each conversion does.

Choosing a Type

DataRecommended type
Counts, indexes, ages, quantitiesint
Timestamps in milliseconds, file sizes, large IDslong
Measurements, scientific values, coordinatesdouble
Money, prices, tax, interestBigDecimal (or long holding the smallest unit, such as paise)
Integers that can exceed 9.2 × 10¹⁸BigInteger
Raw binary databyte / byte[]
Large arrays where memory mattersfloat[], short[], byte[]
A numeric value that may be absentWrapper type (Integer) or OptionalInt

byte and short do not make arithmetic faster: the JVM promotes them to int for every operation. Use them only for compact storage or for formats that require them.

Conversions Between Types

Widening conversions to a larger type happen automatically and never lose magnitude:

byte → short → int → long → float → double

Narrowing conversions require an explicit cast and can lose data:

long big = 9_000_000_000L;
int truncated = (int) big;       // 410065408: high bits discarded
double price = 3.99;
int whole = (int) price;         // 3: fraction truncated, not rounded

Converting long to float or double is widening, but can lose precision for values above about 2⁵³ (for double) or 2²⁴ (for float), because the floating-point type cannot store every digit.

Practical Example: Inspecting the Number Types

import java.math.*;
import java.util.*;

public class NT {
    static String describe(Number n) {
        return String.format("%-11s int=%d long=%d double=%s", n.getClass().getSimpleName(), n.intValue(), n.longValue(), n.doubleValue());
    }

    public static void main(String[] args) {
        System.out.printf("%-7s %5s %22s %22s%n", "type", "bits", "min", "max");
        System.out.printf("%-7s %5d %22d %22d%n", "byte", Byte.SIZE, Byte.MIN_VALUE, Byte.MAX_VALUE);
        System.out.printf("%-7s %5d %22d %22d%n", "short", Short.SIZE, Short.MIN_VALUE, Short.MAX_VALUE);
        System.out.printf("%-7s %5d %22d %22d%n", "int", Integer.SIZE, Integer.MIN_VALUE, Integer.MAX_VALUE);
        System.out.printf("%-7s %5d %22d %22d%n", "long", Long.SIZE, Long.MIN_VALUE, Long.MAX_VALUE);
        System.out.printf("%-7s %5d %22s %22s%n", "float", Float.SIZE, Float.MIN_VALUE, Float.MAX_VALUE);
        System.out.printf("%-7s %5d %22s %22s%n", "double", Double.SIZE, Double.MIN_VALUE, Double.MAX_VALUE);

        List<Number> values = List.of(42, 9_000_000_000L, 3.99f, 2.75, (byte) -5,
                new BigInteger("123456789012345678901234567890"), new BigDecimal("1499.995"));
        for (Number n : values) System.out.println(describe(n));
    }
}

Output:

type     bits                    min                    max
byte        8                   -128                    127
short      16                 -32768                  32767
int        32            -2147483648             2147483647
long       64   -9223372036854775808    9223372036854775807
float      32                1.4E-45           3.4028235E38
double     64               4.9E-324 1.7976931348623157E308
Integer     int=42 long=42 double=42.0
Long        int=410065408 long=9000000000 double=9.0E9
Float       int=3 long=3 double=3.990000009536743
Double      int=2 long=2 double=2.75
Byte        int=-5 long=-5 double=-5.0
BigInteger  int=1312754386 long=-4362896299872285998 double=1.2345678901234568E29
BigDecimal  int=1499 long=1499 double=1499.995

The table, built from each wrapper's SIZE, MIN_VALUE, and MAX_VALUE constants, confirms that float and double report their smallest positive values as the minimum. The second part passes values of every numeric class through the same describe method, which accepts any Number, and shows what the Number conversions do:

  • Long 9,000,000,000 converted to int wraps to 410,065,408 because it does not fit in 32 bits.
  • Float 3.99, widened to double, reveals that it was only ever stored as approximately 3.99.
  • BigInteger converted to int and long keeps only the low-order bits, producing unrelated numbers, and its double loses all but about 16 significant digits.

Each of these conversions compiles without a warning, which is exactly why choosing the right type at the start matters.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Number Types and get answers drawn from it.

Signed-in readers only.