I know that ==
has some issues when comparing two Strings
. It seems that String.equals()
is a better approach. Well, I'm doing JUnit testing and my inclination is to use assertEquals(str1, str2)
. Is this a reliable way to assert two Strings contain the same content? I would use assertTrue(str1.equals(str2))
, but then you don't get the benefit of seeing what the expected and actual values are on failure.
On a related note, does anyone have a link to a page or thread that plainly explains the problems with str1 == str2
?
You should always use .equals()
when comparing Strings
in Java.
JUnit calls the .equals()
method to determine equality in the method assertEquals(Object o1, Object o2)
.
So, you are definitely safe using assertEquals(string1, string2)
. (Because String
s are Object
s)
Here is a link to a great Stackoverflow question regarding some of the differences between ==
and .equals()
.
assertEquals
uses the equals
method for comparison. There is a different assert, assertSame
, which uses the ==
operator.
To understand why ==
shouldn't be used with strings you need to understand what ==
does: it does an identity check. That is, a == b
checks to see if a
and b
refer to the same object. It is built into the language, and its behavior cannot be changed by different classes. The equals
method, on the other hand, can be overridden by classes. While its default behavior (in the Object
class) is to do an identity check using the ==
operator, many classes, including String
, override it to instead do an "equivalence" check. In the case of String
, instead of checking if a
and b
refer to the same object, a.equals(b)
checks to see if the objects they refer to are both strings that contain exactly the same characters.
Analogy time: imagine that each String
object is a piece of paper with something written on it. Let's say I have two pieces of paper with "Foo" written on them, and another with "Bar" written on it. If I take the first two pieces of paper and use ==
to compare them it will return false
because it's essentially asking "are these the same piece of paper?". It doesn't need to even look at what's written on the paper. The fact that I'm giving it two pieces of paper (rather than the same one twice) means it will return false
. If I use equals
, however, the equals
method will read the two pieces of paper and see that they say the same thing ("Foo"), and so it'll return true
.
The bit that gets confusing with Strings is that the Java has a concept of "interning" Strings, and this is (effectively) automatically performed on any string literals in your code. This means that if you have two equivalent string literals in your code (even if they're in different classes) they'll actually both refer to the same String
object. This makes the ==
operator return true
more often than one might expect.
In a nutshell - you can have two String objects that contain the same characters but are different objects (in different memory locations). The == operator checks to see that two references are pointing to the same object (memory location), but the equals() method checks if the characters are the same.
Usually you are interested in checking if two Strings contain the same characters, not whether they point to the same memory location.
Yes, it is used all the time for testing. It is very likely that the testing framework uses .equals() for comparisons such as these.
Below is a link explaining the "string equality mistake". Essentially, strings in Java are objects, and when you compare object equality, typically they are compared based on memory address, and not by content. Because of this, two strings won't occupy the same address, even if their content is identical, so they won't match correctly, even though they look the same when printed.
http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/
public class StringEqualityTest extends TestCase {
public void testEquality() throws Exception {
String a = "abcde";
String b = new String(a);
assertTrue(a.equals(b));
assertFalse(a == b);
assertEquals(a, b);
}
}
The JUnit assertEquals(obj1, obj2)
does indeed call obj1.equals(obj2)
.
There's also assertSame(obj1, obj2)
which does obj1 == obj2
(i.e., verifies that obj1
and obj2
are referencing the same instance), which is what you're trying to avoid.
So you're fine.
"The ==
operator checks to see if two Objects
are exactly the same Object
."
http://leepoint.net/notes-java/data/strings/12stringcomparison.html
String
is an Object
in java, so it falls into that category of comparison rules.