11

I'm running this code with JDK 1.4 and 1.5 and get different results. Why is it the case?

String str = "";
int test = 3;

str = String.valueOf(test);
System.out.println("str[" + str + "]\nequals result[" + (str == "3") + "]");

if (str == "3") {
    System.out.println("if");
} else {
    System.out.println("else");
}

outputs:

  • on jdk 1.4

    str[3]
    equals result[true]
    if
    
  • on jdk 1.5

    str[3]
    equals result[false]
    else
    
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
omgeeeee
  • 131
  • 6
  • 7
    String equality is checked with `"3".equals(str)` and not with `==` operator. – Narendra Pathai Aug 01 '13 at 04:48
  • This has nothing to do with the difference between JDK's but your understanding of how `String` comparison works in Java. Check out the link provided in my previous comment – MadProgrammer Aug 01 '13 at 04:51
  • to compare object equality in java you have to use `equals` , using == if they are refering to the same object... if they were interned then that's you get true. – nachokk Aug 01 '13 at 04:51
  • 1
    @NarendraPathai I think the question is why the output is different with jdk 1.4 and 1.5. – assylias Aug 01 '13 at 04:52
  • @omgeeeee I have rephrased your question - please check that this is what you meant. – assylias Aug 01 '13 at 04:54
  • @assylias you're right!! why the output is different with jdk 1.4 and 1.5 .... – omgeeeee Aug 01 '13 at 04:56
  • @assylias Aha I got it now – Narendra Pathai Aug 01 '13 at 05:07
  • I tried it myself and to my surprise the outputs are different. – Aniket Thakur Aug 01 '13 at 05:12
  • 1
    @assylias This has something to do with interning of strings behavior being different in 1.4 and 1.5. What are your takes? – Narendra Pathai Aug 01 '13 at 05:17
  • @NarendraPathai Both outputs are valid and I can't remember the last time I worked on 1.4 so it is more of a curiosity than a real issue! – assylias Aug 01 '13 at 05:20
  • @MadProgrammer: it *has* to do with the difference in the `String.valueOf` implementation of the different JDKs *and* it is **not** a duplicate of the linked-to-question, it's more specific. Reading that other question will certainly *help* understand the answers here, but they don't themselves answer it. – Joachim Sauer Aug 01 '13 at 05:33
  • @JoachimSauer How? Your comparison `if (str == "3")` is invalid and will never likely be equal – MadProgrammer Aug 01 '13 at 05:35
  • @MadProgrammer: that's true, but there's nothing wrong with trying to understand *why* it produces different outputs (and *why it's wrong to write it that way*). And explaining *why* something is bad in this particular instance helps more than just saying "that's bad, don't do it". – Joachim Sauer Aug 01 '13 at 05:37

4 Answers4

11

According to this page, the Integer#toString method (which is called by String#valueOf(int)) is implemented like this in 1.4:

public static String toString(int i) {  
    switch(i) {  
        case Integer.MIN_VALUE: return "-2147483648";  
        case -3: return "-3";  
        case -2: return "-2";  
        case -1: return "-1";  
        case 0: return "0";  
        case 1: return "1";  
        case 2: return "2";  
        case 3: return "3";  
        case 4: return "4";  
        case 5: return "5";  
        case 6: return "6";  
        case 7: return "7";  
        case 8: return "8";  
        case 9: return "9";  
        case 10: return "10";  
    }  
    char[] buf = (char[])(perThreadBuffer.get());  
    int charPos = getChars(i, buf);  
    return new String(buf, charPos, 12 - charPos);  
}

That would explain your result because the string literal "3" is interned and "3" == "3" always returns true.

You can try with 10 and 11 to verify this.

Note: as already mentioned, the javadoc of Integer#toString does not say whether the returned string will be interned or not so both outputs in your question are equally valid.

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

This is an implementation detail that is not specified by the JLS.

The reference equality operator == checks to see whether two variables point to the same actual object, whereas the equals method checks to see whether two variables' values are "equal" in some way that may be determined by the programmer. In this case, it appears that the 1.4 JVM is taking advantage of the fact that Strings are immutable to reuse the same copy of the string "3" when you call valueOf and the 1.5 JVM is not. Both options are perfectly legal, and you should not depend on any particular such behavior.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
1

From java 5 string.valueof() is expected to return new string. rather than intern(ed) (shared) string!

Consider following example

    int test = 3;
    String str = String.valueOf(test);
    String str2 = String.valueOf(test);

    if(str == str2)
        System.out.println("valueOf return interned string");
    else
        System.out.println("valueOf does not return interned string");

Output in java >=5

valueOf does not return interned string

But in java 4 output is

valueOf return interned string

That explains the behavior!

Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
0

If you are using "==" operator on operation of String literals, then it depends on the whether the string literal value is present on "String Pool" or not, in your case variable "str" is a string JVM first checks on "String Pool" if it is found then it returns TRUE else FALSE. Try the following code with the intern() method, to make the string literal available on "String Pool"

 String str = "";
 int test = 3;

 str = String.valueOf(test).intern();

 System.out.println("str[" + str + "]\nequals result[" + (str == "3") + "]");

 if (str == "3") {
     System.out.println("if");
 } else {
     System.out.println("else");
 }

according to documentation for intern() method: intern() method searches an internal table of strings for a string equal to this String. If the string is not in the table, it is added. Answers the string contained in the table which is equal to this String. The same string object is always answered for strings which are equal.

Well "==" operation is not recommended for string comparison. use equals() or equalsIgnoreCase() method().

I tried even in java 1.7 without intern() the output is

str[3]
equals result[false]
else

with intern() the output comes to:

str[3]
equals result[true]
if

This is not the problem of jdk 1.4 and 1.5 this is a "logical error".

Vishrant
  • 15,456
  • 11
  • 71
  • 120