1

I would like to check if strings are accidentally compared with the == operator. My approach is to try to create new strings in the testcases instead of using string literals, so that comparisons like actualString == testParameter evaluate to false in the test subject, even though the contents of the strings are equal. This hopefully creates unexpected behaviour and leads to test failure. To do this I need to create a new string object in Java. How can I do so reliably?

String a = "I am the same.";
String b = "I am the same."; // Does not create a new String.
String c = new String("I am the same."); 
String d = new StringBuilder().append("I am the same.").toString();

Are the last two lines guaranteed to create new string objects? If you know of another approach, please let me know.

phobic
  • 914
  • 10
  • 24
  • 1
    You can't "prevent" such things. whoever alters your code, can, actually, alter your code, whether it's good or not. besides, Unit tests can be altered as well. – Stultuske Apr 06 '16 at 07:07
  • I will rephrase the question. I want to check if the == operator is used. – phobic Apr 06 '16 at 07:09
  • What do you mean 'create a new string object in Java ... reliably?' Doesn't the JVM already create new strings reliably? Whenever strings are created? – ifly6 Apr 06 '16 at 07:09
  • 2
    Use some kind of static analysis tool that finds uses of `==` with Strings. This problem isn't solved with unit tests, it's solved with proper education of Java features. – Savior Apr 06 '16 at 07:10
  • In the example, a == b evaluates to true, as they point to the same instance. – phobic Apr 06 '16 at 07:10
  • @phobic the only way to do that (without mistakes) is to parse through your files. – Stultuske Apr 06 '16 at 07:11
  • You may be looking for this: http://stackoverflow.com/questions/767372/java-string-equals-versus Parse through the source code, look for variable names declared with `String` before it. Find those variable names, if those variable names are ever separated using `==`, then flag it and return all flags to the user. – ifly6 Apr 06 '16 at 07:12
  • 2
    I simply don't understand the minus 4. What fundamentally is wrong with this question? Remember that questions are the life blood of this site. – Bathsheba Apr 06 '16 at 07:12
  • @ifly6 that's not even close to what he's looking for – Stultuske Apr 06 '16 at 07:12
  • You might want to use something like [Google's errorprone](http://errorprone.info/bugpattern/StringEquality), which can check for this; you can make that a compile-time error. – Andy Turner Apr 06 '16 at 07:13
  • A good code-analysis tool could help you.. – TheLostMind Apr 06 '16 at 07:13
  • 1
    In answer to your question: `c` *is* guaranteed to be a different object (that's what `new` means). I don't know if `d` is *guaranteed* to be a different object, but it almost certainly will, since interning the result is rarely going to be a useful thing to do. – Andy Turner Apr 06 '16 at 07:15
  • Might have to use static analysis – Sajeev Apr 06 '16 at 07:18

3 Answers3

7

"I am the same." == new String("I am the same.") is guaranteed to be false.

BUT, instead of unnecessarily cluttering your tests, you should use a static analysis tool, such as FindBugs, which has a rule just for that:

Comparison of String objects using == or != (ES_COMPARING_STRINGS_WITH_EQ)

assylias
  • 321,522
  • 82
  • 660
  • 783
0

If you use == to compare objects it will check if it's the same object so it checks if the memory addresses of the objects are the same.

The string class overrides the equals() method and checks for content.

If you're creating a string like this

String s1 = "Hi";

Java will put "Hi" in the so called string literal pool so if you are creating a second string

String s2 = "Hi"; 

Java will not create a second Object but will refer to the "Hi" in the string literal pool.

Now you could do compare the two strings like s1 == s2 and it would be true because the two references s1 and s2 point to the same object.

What the sb.toString() method internally does is new String() and if you declare a string like this a new object will be created and the comparison with == will return false because the two references obviously don't point at the same object.

Dimitrios Begnis
  • 823
  • 6
  • 16
0

The javadoc of the String class states that it creates a new String with a copy of the passed argument. So it is guaranteed to be a new instance.

Initializes a newly created {@code String} object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of {@code original} is needed, use of this constructor is unnecessary since Strings are immutable.

tak3shi
  • 2,305
  • 1
  • 20
  • 33