Grafvision - Fotolia
Sometimes, the Java String class is referred to as the 'messed up object type' because it seemingly breaks all the established rules of objects and components. One such rule has to do with the evaluation of equality, or more specifically, how to properly perform Java object comparisons in code.
Let's try to clarify the Java String comparison confusion when it comes to String equality.
In Java, all objects are created with the special new keyword -- with one major exception. String objects have been afforded a shortcut, which makes it possible to create a String with the new keyword.
The shortcut is demonstrated below. Note how this syntax is something you'd rarely see in code.
/*You can use new with Strings, but you're not supposed to.*/
String newKeyword = new String("new");
/*String can be created easily without using the new keyword.*/
String noNewKeyword = "not new";
The String pool
A few interesting things happen behind the scenes when you create a String instance, especially when you chose not to use the new keyword. Strings are constantly used in Java programs. In typical applications, there are always a bunch of common Strings that get used over and over.
Imagine a busy web-based application that needs to schedule something. How many times do you think the names of months or days of the week get repeated on a per user basis? What if there were thousands of users that simultaneously hit the site? If each String representing a day or a month was given a separate memory space, the data duplication would consume an immense amount of memory.
When a String is created, the value of the instance is put into something called a String pool, which helps optimize the efficiency of our Java programs. When a new String matches the value of a String in the pool, the Java Virtual Machine (JVM) will point the new instance to the existing String rather than setting aside a new chunk of memory.
For example, if the month March occurs 2,000 times in a Java application, rather than March being duplicated 2,000 times, there will only be one actual instance, with each of the 2,000 String variables simply pointing to this single memory location. JVM helpfully manages it in an efficient way. Of course, this built-in efficiency can sometimes cause some problems, especially when it comes to Java String comparisons.
A Java String comparison for equality is a common practice in every computer application. By working with primitive types, we know that int and char and boolean values are compared with the double equals sign, ==. We also know that when we compare objects for equality, we need to use the .equals method, because when you use the == with objects, you compare the memory locations of the objects, as opposed to the identity of the objects themselves.
Take a look at the following code block, which compares two java.awt.Color objects:
java.awt.Color c1 = new java.awt.Color(225,225,225); java.awt.Color c2 = new java.awt.Color(225,225,225); System.out.println(c1==c2); /* prints false */ System.out.println(c1.equals(c2)); /* prints true */
Notice how it generates a false result when the two Color objects are compared with the ==, but it generates a true result when the two Color objects are compared with the .equals method. This is the type of result that we would expect because the two objects are indeed the same color, with all the same Red Green Blue values.
Because the two objects were created individually with the new keyword, each instance stores its information in a separate and isolated memory location. When you use the == to compare objects, you compare memory locations. Two objects that are created separately, such as the Color objects c1 and c2 in the code block, will return a == comparison of false.
However, the two Color objects -- c1 and c2 -- represent the same color. Logically, the two colors are the same. A proper comparison of two objects should be done with the .equals method. When colors c1 and c2 are compared with the .equals method, we get a result of true, which indicates that the two colors are indeed the same.
To get a proper Java String comparison with primitive types, use the ==. But with objects, the == compares memory locations. To get a proper evaluation of the equality of objects, you must use the .equals method. However, the String pool creates a bit of an exception to this rule.
Java String comparison nuances
When you optimize String pool usage, the JVM sets aside a single memory location that can be pointed at by references to the same character String. The use of the String pool helps optimize memory use, but it also results in the == generating accurate results when you compare String objects.
String oneEh = "one"; String oneBee = "one"; System.out.println(oneEh==oneBee); /* prints true */ System.out.println(oneEh.equals(oneBee)); /* prints true */
We have worked hard to establish a rule that says objects should be compared with the .equals method, and primitive types must be compared with the ==. But suddenly, it appears that String objects can be accurately compared with the ==. Well, it will usually generate an accurate comparison of String objects, but sometimes it won't.
It's that lack of dependability that tells you why you should never compare String objects with the ==.
New String objects
For the most part, the String pool is used to efficiently manage String objects in memory. However, when the new keyword is used in conjunction with String object creation, the String that's created is given a separate, isolated memory location that is not shared with any other String objects in the application. When the new keyword is used in conjunction with String object creation, comparisons of String that share a common character sequence will generate a false value when you use the ==.
String oneEh = new String("one"); String oneBee = new String("one"); System.out.println(oneEh==oneBee); /* prints false */ System.out.println(oneEh.equals(oneBee)); /* prints true */
Since String objects are typically created without the new keyword, Java String comparisons that use a == will typically work. But with programming, we don't like results that typically work, we like results that always work.
The main lesson to learn is that when you compare objects -- whether it's a String or a Color -- to get a true representation of the equality of the objects, use the .equals method, and only use the == when you really mean to compare memory locations.