Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Every competent Java programmer knows that you need to use String.equals() to compare a string, rather than == because == checks for reference equality.

When I'm dealing with strings, most of the time I'm checking for value equality rather than reference equality. It seems to me that it would be more intuitive if the language allowed string values to be compared by just using ==.

As a comparison, C#'s == operator checks for value equality for strings. And if you really needed to check for reference equality, you can use String.ReferenceEquals.

Another important point is that Strings are immutable, so there is no harm to be done by allowing this feature.

Is there any particular reason why this isn't implemented in Java?

share|improve this question
You might want to look at Scala, where == is object equality and eq is reference equality (ofps.oreilly.com/titles/9780596155957/…). –  Giorgio Apr 2 '13 at 11:12
Just as a note, and this may not help you, but as far as I remember, you can compare string literals with an '==' –  Kgrover Apr 2 '13 at 16:07
@Kgrover: you can, but that's just a convenient by-product of reference equality and how Java aggressively optimizes string matching literals into references to the same object. In other words, it works, but for the wrong reasons. –  tdammers Apr 2 '13 at 19:29
@tdammers Yep, I agree. It was just a point I was trying to make. –  Kgrover Apr 2 '13 at 20:13
IIRC, in C#, the == operator always maps to equals() method (when objects are involved) - probably because that's the more common case; Reference identity requires an explicit function call. –  aviv Apr 3 '13 at 2:55

6 Answers 6

up vote 71 down vote accepted

I guess it's just consistency, or "principle of least astonishment". String is an object, so it would be surprising if was treated differently than other objects.

At the time when Java came out (~1995), merely having something like String was total luxury to most programmers who were accustomed to representing strings as null-terminated arrays. String's behavior is now what it was back then, and that's good; subtly changing the behavior later on could have surprising, undesired effects in working programs.

As a side note, you could use String.intern() to get a canonical (interned) representation of the string, after which comparisons could be made with ==. Interning takes some time, but after that, comparisons will be really fast.

Addition: unlike some answers suggest, it's not about supporting operator overloading. The + operator (concatenation) works on Strings even though Java doesn't support operator overloading; it's simply handled as a special case in the compiler, resolving to StringBuilder.append(). Similarly, == could have been handled as a special case.

Then why astonish with special case + but not with ==? Because, + simply doesn't compile when applied to non-String objects so that's quickly apparent. The different behavior of == would be much less apparent and thus much more astonishing when it hits you.

share|improve this answer
Special cases add astonishment. –  Blrfl Apr 2 '13 at 21:13
Strings were a luxury in 1995? Really?? Look at the history of computer languages. The number of languages that had some type of string at the time would far outnumber those that did not. How many languages besides C and it's descendents used null terminated arrays? –  WarrenT Apr 3 '13 at 0:27
@WarrenT: Sure, some (if not most) languages had some type of string, but Unicode-capable, garbage-collected strings were a novelty in 1995, I think. For example, Python introduced Unicode strings with version 2.0, year 2000. Choosing immutability was also a controversial choice at that time. –  Joonas Pulakka Apr 3 '13 at 6:14
@JoonasPulakka Then maybe you should edit your answer to say that. Because as it stands, the “total luxury” part of your answer is quite wrong. –  svick Apr 3 '13 at 18:45
Interning has a cost: you get a string that will never ever be deallocated. (Well, not unless you use your own interning engine that you can throw away.) –  Donal Fellows Apr 3 '13 at 19:10

James Gosling, the creator of Java, explained it this way back in July 2000:

I left out operator overloading as a fairly personal choice because I had seen too many people abuse it in C++. I've spent a lot of time in the past five to six years surveying people about operator overloading and it's really fascinating, because you get the community broken into three pieces: Probably about 20 to 30 percent of the population think of operator overloading as the spawn of the devil; somebody has done something with operator overloading that has just really ticked them off, because they've used like + for list insertion and it makes life really, really confusing. A lot of that problem stems from the fact that there are only about half a dozen operators you can sensibly overload, and yet there are thousands or millions of operators that people would like to define -- so you have to pick, and often the choices conflict with your sense of intuition.

share|improve this answer
Ah, yes, the old "lets' blunt the pointy tool so the oafs won't hurt themselves" excuse. –  Blrfl Apr 2 '13 at 11:38
@Blrfl: If a tool creates more problems than it solves it is not a good tool. Of course, deciding whether this is the case with operator overloading could turn into a very long discussion. –  Giorgio Apr 2 '13 at 11:43
-1. This doesn't answer the question at all. Java does have operator overloading. The == operator is overloaded for objects and primitives. The + operator is overloaded for byte, short, int, long, float, double, String and probably a couple of others I forgot. It would have been perfectly possible to overload == for String as well. –  Jörg W Mittag Apr 2 '13 at 13:04
@Jorg - no it does not. Operator overloading is impossible to define at the user level. There are indeed some special cases in the compiler but that hardly qualifies –  AZ01 Apr 2 '13 at 14:58
@Blrfl: I don't mind the oafs hurting themselves. It's when they accidentially poke my eye out that I get annoyed. –  Jonas Apr 2 '13 at 21:21

In Java, there is no operator overloading whatsoever, and that's why the comparison operators are only overloaded for the primitive types.

The 'String' class is not a primitive, thus it does not have an overloading for '==' and uses the default of comparing the address of the object in the computer's memory.

I'm not sure, but I think that in Java 7 or 8 oracle made an exception in the compiler to recognize str1 == str2 as str1.equals(str2)

share|improve this answer
"I'm not sure, but I think that in Java 7 or 8 oracle made an exception in the compiler to recognize str1 == str2 as str1.equals(str2)": I would not be surprised: Oracle seems to be less concerned with minimalism than Sun was. –  Giorgio Apr 2 '13 at 10:55
If true, that's a very ugly hack since it means there's now one class the language treats differently from all others and breaks code that compares references. :-@ –  Blrfl Apr 2 '13 at 11:02
@Blrfl: Yes, I agree, but I'm not sure that that's true. Just something from the top of my head. I'm searching for a source. –  Gilad Naaman Apr 2 '13 at 11:04
@Blrfl: How can it break code that compares references? Aren't two strings that have the same reference by necessity also equal? –  Williham Totland Apr 2 '13 at 11:19
@Brlfl: While that is true, that sounds like an exceptionally bad thing to rely on in the first place, as strings are immutable, internable objects. –  Williham Totland Apr 2 '13 at 11:37

Java doesn't support operator overloading, which means == only applies to primitive types or references. Anything else requires invocation of a method. Why the designers did this is a question only they can answer. If I had to guess, it's probably because operator overloading brings complexity they weren't interested in adding.

I'm no expert in C#, but the designers of that language appear to have set it up such that every primitive is a struct and every struct is an object. Because C# allows operator overloading, that arrangement makes it very easy for any class, not just String, to make itself work in the "expected" way with any operator. C++ allows the same thing.

share|improve this answer
"Java doesn't support operator overloading, which means == only applies to primitive types or references. Anything else requires invocation of a method.": One could add that if == meant string equality, we would need another notation for reference equality. –  Giorgio Apr 2 '13 at 11:03
@Giorgio: Exactly. See my comment on Gilad Naaman's answer. –  Blrfl Apr 2 '13 at 11:05
Although that can be solved by a static method that compares the references of two objects (or an operator). Like in C#, for example. –  Gilad Naaman Apr 2 '13 at 11:08
@GiladNaaman: That would be a zero-sum game because it causes the opposite problem to what Java has now: equality would be on an operator and you'd have to invoke a method to compare references. Further, you'd have to impose the requirement that all classes implement something that can be bound to ==. That's effectively adding operator overloading, which would have tremendous implications on the way Java is implemented. –  Blrfl Apr 2 '13 at 11:16
@Blrfl: Not really. There will always be a defined way to compare reference (ClassName.ReferenceEquals(a,b)), and a default == operator and Equals method both pointing to ReferenceEquals. –  Gilad Naaman Apr 2 '13 at 11:29

This has been made different in other languages.

In Object Pascal (Delphi/Free Pascal) and C#, the equality operator is defined to compare values, not references, when operating on strings.

Particularly in Pascal, string is a primitive type (one of the things I really love about Pascal, getting NullreferenceException just because of an uninitialized string is simply irritating) and have copy-on-write semantics thus making (most of time) string operations very cheap (in other words, only noticeable once you start concatenating multi-megabyte strings).

So, it's a language design decision for Java. When they designed the language they followed the C++ way (like Std::String) so strings are objects, which is IMHO an hack to compensate of C lacking an real string type, instead of making strings an primitive (which they are).

So for a reason why, I can only speculate they made that to easy on their side and not coding the operator make an exception on compiler to strings.

share|improve this answer
how does this answer the question asked? –  gnat Apr 3 '13 at 12:53
See last sentence (which I separated in a proper paragraph in a edit). –  Fabricio Araujo Apr 3 '13 at 18:23
IMHO, String should have been a primitive type in Java. Unlike other types, the compiler needs to know about String; further, operations on it will be sufficiently common that for many kinds of application they may pose a performance bottleneck (which could be eased by native support). A typical string [lowercase] would have an object allocated on the heap to hold its contents, but no "normal" reference to that object would exist anywhere; it could thus be a single-indirected Char[] or Byte[] rather than having to be a Char[] indirected through another object. –  supercat Feb 25 '14 at 13:27

Java seems to have been designed to uphold a fundamental rule that the == operator should be legal any time one operand can be converted to the type of the other, and should compare the result of such conversion with the non-converted operand.

This rule is hardly unique to Java, but it has some far-reaching (and IMHO unfortunate) effects on the design of other type-related aspects of the language. It would have been cleaner to specify the behaviors of == with regard to particular combinations of operand types, and forbid combinations of types X and Y where x1==y1 and x2==y1 wouldn't imply x1==x2, but languages seldom do that [under that philosophy, double1 == long1 would either have to indicate whether double1 is not an exact representation of long1, or else refuse to compile; int1==Integer1 should be forbidden, but there should be a convenient and efficient non-throwing means of testing whether an object is a boxed integer with particular value (comparison with something that isn't a boxed integer should simply return false)].

With regard to applying the == operator to strings, if Java had forbidden direct comparisons between operands of type String and Object, it could have pretty well avoided surprises in the behavior of ==, but there's no behavior it could implement for such comparisons that wouldn't be astonishing. Having two string references kept in type Object behave differently from references kept in type String would have been far less astonishing than having either of those behaviors differ from that of a legal mixed-type comparison. If String1==Object1 is legal, that would imply that the only way for the behaviors of String1==String2 and Object1==Object2 to match String1==Object1 would be for them to match each other.

share|improve this answer
I must be missing something, but IMHO == on objects should simply call (null-safe) equals and something else (e.g., === or System.identityEqual) should be used for the identity comparison. Mixing primitives and objects would be initially forbidden (there was no autoboxing before 1.5) and then some simple rule could be found (e.g. null-safe unbox, then cast, then compare). –  maaartinus Nov 17 '14 at 8:33
@maaartinus: A good language design should use separate equality operators for value and reference equality. While I agree that conceptually it would have been possible to have an int==Integer operator return false if the Integer is null, and otherwise compare values, that approach would have been unlike the behavior of == in all other circumstances, where it unconditionally coerces both operands to the same type before comparing them. Personally I wonder if auto-unboxing was put in place in an effort to allow int==Integer to have a behavior that wasn't nonsensical... –  supercat Nov 17 '14 at 16:16
...since autoboxing the int and doing a reference comparison would have been silly [but wouldn't always fail]. Otherwise, I see no reason to allow an implicit conversion that can fail with an NPE. –  supercat Nov 17 '14 at 16:20
I think that my idea is consistent. Just keep it mind that in the better world, == has nothing to do with identityEquals. +++ "separate equality operators for value and reference equality" - but which ones? I'd consider both primitive == and equals as doing value comparison in the sense that equals looks at the value of the reference. +++ When == meant equals, then int==Integer SHOULD do autoboxing and compare the references using null-safe equals. +++ I'm afraid, my idea is not really mine, but just what Kotlin does. –  maaartinus Nov 18 '14 at 2:04
@maaartinus: If == never tested reference equality, then it could sensibly perform a null-safe value-equality test. The fact that it does test reference equality, however, severely limits how it can handle mixed reference/value comparisons without inconsistency. Note also that Java is fixed on the notion that operators promote both operands to the same type, rather than yielding special behaviors based upon the combinations of types involved. For example, 16777217==16777216.0f returns true because it performs a lossy conversion of the first operand to float, while a... –  supercat Nov 18 '14 at 4:54

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.