Integer Class
java.lang.Integer is the wrapper class for the primitive type int. An Integer object holds a single int value, which lets whole numbers be used where Java requires objects: in collections, generics, and nullable fields. The class also provides constants and static utility methods for parsing text into numbers, converting numbers into text in different bases, comparing values, and working with individual bits. Long, Short, and Byte follow exactly the same design for their primitive types.
Why a Wrapper Class Is Needed
Primitives are not objects, and generic types accept only objects:
List<int> scores; // compile error
List<Integer> scores; // correct
Integer is also used when "no value" must be representable, such as a database column that allows NULL, since a primitive int always has a value.
Creating Integer Objects
Integer a = 42; // autoboxing: the compiler calls Integer.valueOf(42)
Integer b = Integer.valueOf(42); // explicit
Integer c = Integer.valueOf("42"); // from text
int d = a; // unboxing: the compiler calls a.intValue()
The constructor new Integer(42) is deprecated for removal and should not be used. Integer.valueOf is preferred because it can return cached instances.
Autoboxing and Unboxing
The compiler converts between int and Integer automatically:
List<Integer> list = new ArrayList<>();
list.add(5); // autoboxing: int → Integer
int first = list.get(0); // unboxing: Integer → int
int sum = list.get(0) + 10; // unboxed for arithmetic
This convenience hides two traps.
Unboxing null throws
Integer n = null;
int x = n; // NullPointerException
The compiler inserts n.intValue(), which fails on null. This often surprises code reading from maps:
Map<String, Integer> stock = new HashMap<>();
int count = stock.get("pen"); // NullPointerException: key absent
int safe = stock.getOrDefault("pen", 0); // 0
== compares objects, not values
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b); // true
System.out.println(c == d); // false
System.out.println(c.equals(d)); // true
System.out.println(c.intValue() == d); // true: one side is a primitive, so both are compared as ints
Integer.valueOf caches instances for values from −128 to 127, so small values happen to share an object and == returns true. Larger values are separate objects, so == returns false even though the numbers are equal. Code that works in tests with small numbers can fail in production with larger ones.
Rule: compare Integer objects with equals, or unbox at least one side to int.
Constants
| Constant | Value |
|---|---|
Integer.MAX_VALUE | 2,147,483,647 (2³¹ − 1) |
Integer.MIN_VALUE | −2,147,483,648 (−2³¹) |
Integer.SIZE | 32 (bits) |
Integer.BYTES | 4 |
Parsing Text into Numbers
int a = Integer.parseInt("-42"); // -42 (primitive)
Integer b = Integer.valueOf("42"); // 42 (object)
int hex = Integer.parseInt("ff", 16); // 255
int bin = Integer.parseInt("1010", 2); // 10
long big = Long.parseLong("9000000000"); // values beyond int range need Long
parseInt returns an int; valueOf returns an Integer. Both accept an optional radix (base) from 2 to 36.
Invalid input throws NumberFormatException:
Integer.parseInt("12.5"); // NumberFormatException: For input string: "12.5"
Integer.parseInt(" 42"); // NumberFormatException: whitespace is not allowed
Integer.parseInt(""); // NumberFormatException
Integer.parseInt("3000000000"); // NumberFormatException: out of int range
Input from users, files, or HTTP requests should be stripped and parsed inside a try/catch, or validated first. The practical example below shows a reusable pattern.
Converting Numbers into Text
String s1 = Integer.toString(255); // "255"
String s2 = String.valueOf(255); // "255"
Integer.toBinaryString(10); // "1010"
Integer.toHexString(255); // "ff"
Integer.toOctalString(8); // "10"
Integer.toString(255, 36); // "73": base 36 uses digits and letters
toBinaryString and toHexString represent negative numbers in two's complement: Integer.toHexString(-1) is ffffffff.
For padded or grouped output, use String.format("%05d", n) or "%,d".
Comparing and Arithmetic Helpers
Integer.compare(3, 7); // -1: negative, zero, or positive (safe, no overflow)
Integer.signum(-9); // -1, 0, or 1
Integer.max(4, 9); // 9
Integer.min(4, 9); // 4
Integer.sum(2, 3); // 5
Integer.compare is the correct way to compare two int values in a compareTo or Comparator; subtracting them can overflow. Integer::sum, Integer::max, and Integer::compare are also handy as method references, for example map.merge(key, 1, Integer::sum).
Bit Manipulation
| Method | Example | Result |
|---|---|---|
bitCount(i) | Integer.bitCount(255) | 8 (number of 1 bits) |
highestOneBit(i) | Integer.highestOneBit(100) | 64 |
numberOfTrailingZeros(i) | Integer.numberOfTrailingZeros(8) | 3 |
numberOfLeadingZeros(i) | Integer.numberOfLeadingZeros(1) | 31 |
reverse(i) | Integer.reverse(1) | -2147483648 (bit 0 moved to bit 31) |
rotateLeft(i, n) | Integer.rotateLeft(1, 4) | 16 |
These are used in hashing, compression, graphics, permission flags, and algorithms that work on powers of two.
Unsigned Operations
Java's int is always signed, but Integer can treat its 32 bits as an unsigned value from 0 to 4,294,967,295:
Integer.parseUnsignedInt("4294967295"); // -1 (the same bits, read as a signed int)
Integer.toUnsignedString(-1); // "4294967295"
Integer.toUnsignedLong(-1); // 4294967295L
Integer.divideUnsigned(-2, 2); // 2147483647
Integer.compareUnsigned(-1, 1); // positive: -1 is the largest unsigned value
This is useful when reading binary formats, network protocols, or hash values defined as unsigned 32-bit numbers.
Integer, Long, Short, and Byte
All four wrapper classes provide the same kinds of methods (parseXxx, valueOf, toString, compare, MIN_VALUE/MAX_VALUE, and, for Long, the same bit and unsigned operations). Choose the wrapper that matches the primitive you need. Long.valueOf, Short.valueOf, and Byte.valueOf also cache values from −128 to 127, so the same == warning applies to them.
Practical Example: Validating Quantity Input
A shopping cart receives quantities as text from a web form. The value must be a whole number from 1 to 100; anything else must be rejected without crashing the request.
import java.util.*;
public class IntC {
static OptionalInt parseQuantity(String raw) {
if (raw == null || raw.isBlank()) return OptionalInt.empty();
try {
int q = Integer.parseInt(raw.strip());
return q > 0 && q <= 100 ? OptionalInt.of(q) : OptionalInt.empty();
} catch (NumberFormatException e) {
return OptionalInt.empty();
}
}
public static void main(String[] args) {
for (String s : List.of("3", " 25 ", "0", "abc", "250", "", "7.5")) {
OptionalInt q = parseQuantity(s);
System.out.printf("%-6s -> %s%n", "\"" + s + "\"", q.isPresent() ? q.getAsInt() : "invalid");
}
List<Integer> ids = new ArrayList<>(List.of(10, 20, 30));
ids.remove(Integer.valueOf(20));
System.out.println(ids);
}
}
Output:
"3" -> 3
" 25 " -> 25
"0" -> invalid
"abc" -> invalid
"250" -> invalid
"" -> invalid
"7.5" -> invalid
[10, 30]
parseQuantity handles every way the input can go wrong:
- Missing or blank input is rejected before parsing is attempted.
- Surrounding spaces are removed with
strip(), becauseparseIntrejects whitespace. - Non-numeric text and decimals (
"abc","7.5") makeparseIntthrowNumberFormatException, which is caught and turned into "invalid." - Valid numbers out of range (
0,250) pass parsing but fail the range check.
Returning OptionalInt (a primitive-specialized Optional) makes it impossible for the caller to forget that the value may be missing, and avoids boxing. The last line shows why Integer.valueOf(20) is needed when removing a value from a List<Integer>: ids.remove(20) would call remove(int index) and throw IndexOutOfBoundsException.