Java long Type: Range, Syntax, and Pitfalls
java long type: Understand the Java long type: its 64-bit range, literal syntax, conversion rules, overflow behavior, and the pitfalls that cause subtle numeric bugs.
java long type requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
The Java long type is a 64-bit signed integer stored in two's-complement form. It can represent values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, which makes it the default choice for values that exceed the int range. Most of the complexity around the long type shows up at its boundaries: overflow, conversions, and parsing.
Declaring and Initializing long Variables
A long variable is declared with the long keyword and initialized with an integer literal. When the literal exceeds the int range, the L suffix is required:
long population = 8_000_000_000L; long maxValue = Long.MAX_VALUE; long minValue = Long.MIN_VALUE;
Without the L suffix, the compiler treats the literal as an int and rejects the assignment with an "integer number too large" error. The underscore separators in 8_000_000_000L are ignored by the compiler; they only improve readability for large values.
The Long wrapper class exposes the two boundary constants, Long.MAX_VALUE and Long.MIN_VALUE, which are the largest and smallest representable values. These constants are useful when you need to initialize a variable to an extreme value, such as when tracking a running minimum or maximum.
What Happens at the Range Boundaries
Arithmetic that crosses either boundary does not throw an exception. Because long uses two's-complement representation, the result wraps around silently:
long max = Long.MAX_VALUE; long wrapped = max + 1; System.out.println(wrapped); // -9223372036854775808
The same wrap-around applies to subtraction below Long.MIN_VALUE and to multiplication that exceeds the range. The result is a value that looks plausible but is numerically wrong, which makes overflow bugs difficult to detect in production.
When correctness matters, use the exact-arithmetic methods on Math:
try { long result = Math.addExact(Long.MAX_VALUE, 1); } catch (ArithmeticException e) { // handle the overflow explicitly }
Math.addExact, Math.subtractExact, Math.multiplyExact, and Math.negateExact throw ArithmeticException when the result does not fit in a long. These methods add a small runtime cost compared to plain arithmetic, so they are best used where overflow is a real possibility rather than everywhere.
Converting Between long and Other Numeric Types
Widening conversions, such as int to long, are implicit and lossless. The JVM sign-extends the value, so a negative int becomes a negative long with the same numeric value.
Narrowing conversions require an explicit cast and can lose data. Casting a long to an int keeps only the low 32 bits:
long big = 5_000_000_000L; int truncated = (int) big; // 1,705,032,704, not 5,000,000,000
The cast does not throw an exception; it simply discards the high-order bits. If the original value fits in the target type, the cast is safe, so check the range before casting when the value comes from an untrusted source.
Converting a long to a double or float is also lossy in a different way. A double has a 53-bit mantissa, so any long value above 2^53 cannot be represented exactly. For example, (double) Long.MAX_VALUE rounds to a nearby value rather than preserving all 64 bits.
Parsing and Formatting long Values
The Long class provides parseLong for converting strings and toString for the reverse direction:
long parsed = Long.parseLong("123456789012345"); String formatted = Long.toString(parsed);
Long.parseLong throws NumberFormatException when the input is not a valid decimal integer, including cases where the value is out of the long range. The exception is unchecked, so callers often forget to handle it. In code that parses user input or external data, wrap the call in a try-catch or validate the input first.
Long.valueOf behaves like parseLong but returns a Long object. For values between -128 and 127, the JVM returns cached instances, so repeated calls with the same small value reuse the same object. Outside that range, a new object is allocated on each call.
Common Pitfalls with the Long Wrapper Type
The Long wrapper object does not behave like the primitive in equality checks. Comparing two Long references with == compares object identity, not numeric value:
Long a = 1000L; Long b = 1000L; System.out.println(a == b); // false System.out.println(a.equals(b)); // true
The cached range of -128 to 127 can make == appear to work for small values, which leads to bugs that only appear when the data grows. Always use equals or compare the unboxed primitives.
Autoboxing and unboxing introduce another failure mode. If a Long reference is null, unboxing it to a primitive long throws NullPointerException:
Long value = null; long primitive = value; // NullPointerException
This commonly surfaces when a Long is read from a map or a result set that may contain nulls.
Performance and Memory Considerations
A primitive long occupies 8 bytes on the stack or in an array. A Long object on the heap adds an object header, which typically brings the total footprint to 16 to 24 bytes on modern 64-bit JVMs, depending on alignment and compressed oops settings. In a collection such as ArrayList<Long>, each element also carries a reference, so the memory cost is several times that of a long[] array.
For numeric workloads that process millions of values, prefer primitive arrays or specialized libraries over boxed collections. The JVM can apply escape analysis to eliminate some allocation overhead for short-lived Long objects, but that optimization is not guaranteed and depends on the code path.
When to Choose long Over int
The decision between int and long comes down to the range of values the code must represent. Use long when the value can exceed 2,147,483,647, when the value is a timestamp in milliseconds since the epoch, or when an external API or file format requires a 64-bit integer. Use int when the range is known to fit and memory density matters, such as in large arrays where every byte counts.
The long type is also the right choice for intermediate results in arithmetic that would overflow int. For example, multiplying two int values can exceed the int range, so casting one operand to long before the multiplication avoids silent truncation:
int width = 60_000; int height = 60_000; long area = (long) width * height; // 3,600,000,000, not overflow
Casting one operand is enough because the JVM promotes the other operand to long as well. This pattern is common in geometric and image-processing code where dimensions are large.