Java DISCUSSION

Why does == work for some Java Strings and Integers but fail for others with equal values?

Started by sanjay String equalsreference equalityInteger cacheautoboxingstring pool
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Why does == work for some Java Strings and Integers but fail for others with equal values?

sanjay Java Forum
#1

My command parser compares if (cmd == "START"). It works in a unit test where cmd is assigned from a literal, but fails when cmd comes from reader.readLine(), even though printing both shows identical text. I see the same thing with numbers: two Integer variables both holding 100 compare equal with ==, but two holding 1000 do not.

What is == actually comparing, why does it sometimes appear to work, and what is the correct comparison in each case?

Community replies 5

Re: Why does == work for some Java Strings and Integers but fail for others with equal values?

#2

For primitives such as int, double and char, == compares values. For anything that is an object, including String and Integer, == compares references: it is true only when both sides refer to the very same object. Comparing contents is what equals() is for.

It appears to work with literals because string literals are interned. Every occurrence of "START" in your program refers to one shared object in the string pool, so literal == literal is true. A string produced at run time, by readLine(), new String(...), substring or concatenation of variables, is a new object and not the pooled one.

Re: Why does == work for some Java Strings and Integers but fail for others with equal values?

#3

The correct forms: "START".equals(cmd), with the constant first so that a null cmd gives false instead of a NullPointerException; "START".equalsIgnoreCase(cmd) for a case-insensitive match; and Objects.equals(a, b) when either side may be null.

With input from a serial line or console, call trim() as well. A trailing carriage return from a CRLF line ending makes equals fail, and the two strings look identical when printed. A switch on a String compares with equals semantics, so switch (cmd) { case "START": ... } is safe, but it throws NullPointerException when cmd is null.

Re: Why does == work for some Java Strings and Integers but fail for others with equal values?

#4

The Integer behaviour comes from autoboxing, which calls Integer.valueOf(int). That method is required to cache the values -128 to 127. So with Integer a = 100, b = 100; both variables refer to the same cached object and a == b is true, while Integer a = 1000, b = 1000; normally creates two objects and a == b is false.

Use a.equals(b), or compare primitives with a.intValue() == b.intValue(). A mixed comparison of an Integer with an int unboxes automatically and compares values, but throws NullPointerException if the Integer is null. Long has the same trap, plus one more: Long.valueOf(5).equals(5) is false, because the argument 5 boxes to an Integer and equals checks the type first.

Re: Why does == work for some Java Strings and Integers but fail for others with equal values?

#5

This bites hardest in collections. With a List<Integer> ids, the test ids.get(i) == ids.get(j) compares boxed objects; it passes in tests with small numbers and fails in the field with IDs above 127. With a Map<Long, String>, map.get(5) returns null, because the int literal boxes to an Integer; write map.get(5L).

A relative of the same confusion: list.remove(1) on a List<Integer> removes the element at index 1, not the value 1; for the value use list.remove(Integer.valueOf(1)). And for floating point, == does compare values, but 0.1 + 0.2 == 0.3 is false because of rounding, so compare with a tolerance such as Math.abs(a - b) < 1e-9.

Re: Why does == work for some Java Strings and Integers but fail for others with equal values?

#6

String.intern() returns the pooled instance, so cmd.intern() == "START" would be true, but do not use it as a fix. Nothing is gained over equals, which already checks for the same reference first and only then compares the characters.

Enums are the one kind of object for which == is the recommended comparison. Each constant is a single instance, so state == State.RUNNING is correct, null-safe and type-checked at compile time. For a command parser, converting the text once with Command.valueOf(cmd.trim().toUpperCase(Locale.ROOT)), catching IllegalArgumentException for unknown input, and then switching on the enum removes string comparisons from the rest of the code.

TEP COMMUNITY