Back to Blog
Java

Java int Type: Range, Overflow, and Practical Usage

Understand the Java int type: its 32-bit range, arithmetic promotion, overflow behavior, and how to choose between int, long, and Integer.

Java primitivesInteger overflowAutoboxingNumeric type promotionInteger parsing
Illustration of the Java int type showing its 32-bit range boundary and overflow wrapping behavior.

The Java int type is a 32-bit signed primitive that stores whole numbers from -2,147,483,648 to 2,147,483,647. It is the default choice for integer arithmetic in most Java programs because it requires no object allocation and maps directly to JVM bytecode instructions. Understanding its range, promotion rules, and overflow behavior matters before you write your first loop, because these details determine when int is sufficient and when you need a wider type such as long or BigInteger, or the boxed Integer type.

Declaring and Initializing int Variables

An int variable is declared with the int keyword. Local variables must be assigned a value before they are read; the compiler rejects code that reads an uninitialized local. Instance and static fields, by contrast, default to 0 when an object or class is loaded.

int count = 42; int total; // must be assigned before any read
public class Counter { private int value; // defaults to 0 }

The final modifier prevents reassignment. A final int must be assigned exactly once before it is read; assigning it at the declaration is the standard way to define named constants such as MAX_RETRIES or DEFAULT_PORT.

final int MAX_RETRIES = 3;

Arithmetic Behavior and Type Promotion

When two int values are combined with +, -, *, /, or %, the result is an int. Integer division truncates toward zero, so 7 / 2 evaluates to 3, not 3.5. The modulo operator % returns the remainder with the sign of the dividend.

int a = 7; int b = 2; int quotient = a / b; // 3 int remainder = a % b; // 1

If one operand in a binary operation is a long, float, or double, the int is promoted to that wider type before the operation runs. This is binary numeric promotion, and it is why 5 / 2.0 produces 2.5 while 5 / 2 produces 2. The same rule applies to comparison operators and to method arguments when a widening conversion is available.

Compound assignment operators such as +=, -=, *=, and %= perform an implicit cast back to int. For example, int x = 5; x += 3.7; compiles: the addition is performed in double and the result 8.7 is then truncated to 8 when it is stored in x. The explicit cast is hidden, which can surprise developers who expect a compile error.

Overflow and How to Detect It

Because int is a fixed-width two's complement value, arithmetic that exceeds the range wraps around silently. Integer.MAX_VALUE + 1 evaluates to Integer.MIN_VALUE, and Integer.MIN_VALUE - 1 evaluates to Integer.MAX_VALUE. There is no automatic exception, and the result is often a negative number where a positive one was expected.

int max = Integer.MAX_VALUE; int overflowed = max + 1; // -2147483648

The java.lang.Math class provides exact arithmetic methods that throw ArithmeticException on overflow: addExact, subtractExact, multiplyExact, and negateExact. These are useful in any code where a wrapped value would corrupt the result, such as hash computations or accumulation of counts.

try { int result = Math.addExact(Integer.MAX_VALUE, 1); } catch (ArithmeticException e) { // handle the overflow explicitly }

Overflow also occurs in intermediate expressions. Multiplying two large int values can overflow even when the final result would fit in a long. In that case, cast one operand to long before the multiplication:

long product = (long) a * b;

The cast forces the multiplication to run in 64-bit arithmetic, avoiding the intermediate 32-bit overflow.

int vs Integer: Autoboxing and Performance

Integer is the boxed reference counterpart of int. Autoboxing converts an int to an Integer automatically when the context requires an object, such as when storing values in a List<Integer> or a Map<String, Integer>. Unboxing converts in the reverse direction.

List<Integer> numbers = new ArrayList<>(); numbers.add(42); // autoboxing int first = numbers.get(0); // unboxing

Java requires boxing conversions to reuse the same Integer object for values from -128 to 127, and Integer.valueOf uses a cache in that range. Conversions outside that range generally allocate a new Integer object, though a JVM may cache a wider range. In a hot loop that stores many values into a collection, the allocation cost of boxing can become measurable. The new Integer(value) constructor always allocates a new object, which is why it has been deprecated since Java 9.

Unboxing a null Integer throws NullPointerException. This is a common failure when a collection contains null values or when a database result maps to an Integer that was never set.

Integer maybeNull = getValue(); int value = maybeNull; // NullPointerException if maybeNull is null

Parsing and Converting int Values

Integer.parseInt converts a String to an int. It accepts an optional leading sign and throws NumberFormatException for empty strings, non-digit characters, or values outside the int range. The overload Integer.parseInt(String, int radix) parses values in bases other than 10.

int decimal = Integer.parseInt("1234"); int hex = Integer.parseInt("ff", 16); // 255

For the reverse direction, Integer.toString(int) and String.valueOf(int) produce the decimal representation. Integer.toHexString, Integer.toOctalString, and Integer.toBinaryString produce alternate bases.

String s = Integer.toString(255); // "255" String hex = Integer.toHexString(255); // "ff"

When parsing user input, catching NumberFormatException is necessary because the input cannot be trusted. The Integer class also provides compare, max, min, and sum static methods that avoid the overhead of boxing when working with primitive values.

Choosing Between int and Other Numeric Types

int is the right default for counters, array indices, loop variables, and most whole-number calculations. Use long when a value may exceed 2,147,483,647, such as timestamps in milliseconds or file sizes in bytes. Use byte or short only when memory footprint is a measured constraint in large arrays, because arithmetic on those types is promoted to int anyway. Use BigInteger for arbitrary-precision arithmetic, which is necessary for cryptographic operations or very large combinatorial values but carries a significant performance cost.

TypeBit widthRangeTypical use
byte8-128 to 127Binary data, compact arrays
short16-32,768 to 32,767Legacy formats, compact storage
int32-2,147,483,648 to 2,147,483,647Default integer arithmetic
long64-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807Large counters, timestamps

The decision between int and long should be based on the actual range of values the code can encounter, not on the size of the input. A counter that increments once per request in a high-traffic service can exceed the int range over a long enough period. When the range is uncertain, long is the safer choice, and the JVM handles 64-bit arithmetic efficiently on modern hardware.

Java int Type: Range, Overflow, and When to Use It | RYUSLOG DEV