Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

String equality question

Options
  • 27-05-2004 11:33am
    #1
    Registered Users Posts: 4,666 ✭✭✭


    I had an if statement that was trying to compare 2 strings. Initially I had forgotten they were strings and tested for equality using ==.

    When I ran this the program never went into the if statement. I debugged this and found that the a==b was evaluating to true.

    If it eveluated to true then the program should have went into the if statement, i would have thought. Changing to a.equals(b) works correctly but why did the program not go into the if statement when a==b evaluates to true?


Comments

  • Registered Users Posts: 2,243 ✭✭✭zoro


    I assume this is java?

    I'm not 100% sure on the terminology - but suffice it to say that == can only be used for boolean / int / double / long ... numbers basically (boolean is 0/1 anyway)

    the String.equals() method compares each character at byte level to make sure that the strings are indeed equal.

    I don't think I ever learnt WHY it's like this, I've just programmed around it as there's no other way to do it!


  • Registered Users Posts: 68,317 ✭✭✭✭seamus


    Afaik the "==" operator isn't "equals" when comparing objects. When used with Objects, it checks if the Objects are pointing to the same thing. Only with primitives can it be used to check for equality.
    Afaik, part of Java's optimisation on compile means that if two Strings are the same, bytewise, then their names are pointers to the same object.


  • Registered Users Posts: 4,666 ✭✭✭Imposter


    Sorry, yes it is java.

    The == checks compares the references but even when this returns true the program doesn't go into the statement!


  • Closed Accounts Posts: 47 PhilH


    The == operator compares to see if your two variables (a and b) refer to the same object. The compiler should be efficient about allocating strings, so code like

    String a = "apple";
    String b = "apple";
    if (a == b)
    {
    System.out.println("Okay");
    }


    Should print out the word "Okay". The compiler should have decided it can re-use the object allocated to represent "apple" for both a and b.

    The equals method checks for value equality - in the case of string this means they need to represent the same sequence of characters. So

    String a = "apple";
    String b = "APPLE";
    String c = b.toLowerCase();
    if (a.equals(b))
    {
    System.out.println("Wrong");
    }
    if (a.equals(c))
    {
    System.out.println("Okay");
    }


    will not print the work "Wrong", but will print the "Okay".

    As to the behaviour reported in the original post, I would (trying to be as diplomatic as possible) suggest that either the a==b test was not the only thing governing the execution of the if statement (for example maybe it was and'ed with something), or some other misinterpretation. You are dead right in thinking that if the condition evaluates to true, the if statement should enter its conditional clause.


  • Registered Users Posts: 4,666 ✭✭✭Imposter


    Originally posted by PhilH
    As to the behaviour reported in the original post, I would (trying to be as diplomatic as possible) suggest that either the a==b test was not the only thing governing the execution of the if statement (for example maybe it was and'ed with something), or some other misinterpretation. You are dead right in thinking that if the condition evaluates to true, the if statement should enter its conditional clause.
    You are right that it was and'ed with something but that was also true.
    The entire statement was more or less if( a == 1 && b == c) where a is an int and b and c are Strings (The more or less being proper variable names). Both evaluated individually to true so the entire expression should be true. The debugging was done using JBuilder8 and JDK-1.2.2_011. Would there be something different in the way JBuilder interprets the code to the way it is interpreted when ran? I wouldn't imagine so, but it's the only thing I can think of.


  • Advertisement
  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


    The == checks compares the references but even when this returns true the program doesn't go into the statement!

    Ok...firstly, if you check the actual source code in the string class for the .equals method, I think you'll see that it basically is implemented as :

    return a == b;

    In other words, a.equals(b) is synonymous with a == b : they do exactly the same thing.

    (I could be wrong...I don't have java source installed at the moment, so I'm working from memory).

    I'm guessing that if the code isn't entering the if loop while you use == and the strings are equal, then there's something wrong with yoru code....

    maybe if you posted the working and non-working code?
    (or at least the if statement, and ideally the block of code it is covering)

    jc


  • Registered Users Posts: 68,317 ✭✭✭✭seamus


    Originally posted by Imposter
    You are right that it was and'ed with something but that was also true.
    The entire statement was more or less if( a == 1 && b == c)
    I've always found that containing each individual statement in brackets solves issues like this.
    So
    if ((a == 1) && (b == c))
    I'm not sure. If you check the priority of the operators, it may show up something.

    If may be reading it as
    if( ( a == 1 && b) == c)
    for example.


  • Registered Users Posts: 4,666 ✭✭✭Imposter


    Not working code:
    if (a == 1 && b == c){
    ...
    }
    
    Working code:
    if (a == 1 && b.equals(c)){
    ...
    }
    
    Tried the brackets Seamus but it didn't have any effect.
    The b is a call like m_myInstance.m_var (mightn't be the best implementation but anyways)
    and the c is MyInstance.VAR_CONST where m_myInstance is an instance of the MyInstance class and m_var is a String variable that happens to occasionally be set to VAR_CONST.


  • Closed Accounts Posts: 47 PhilH


    Seamus suggested bracketing the expressions. This is sensible for complicated expressions. However the operator precednece rules for Java insist that a simple expression like

    (a==1 && b==c)

    is exactly the same as

    ((a==1) && (b==c))

    I gotta say, though, that I really don't think bonkey is correct in his assertion.

    The implementation for the Object class's equals() method is to do a reference equality check (as in a==b). However the String class does a value check.

    From the Javadocs for String...
    The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.

    Now back to the odd debugging experience...

    I did some work ages ago where we occasionally saw the debugger point to comment lines and blank lines etc. It turned out that the debugger was pointing at compiled files that were not in synch with the source code, so when it was executing it thought it was on line 84 (say) of the file, but the file had changed and line 84 was now different. Admittedly this was in C++, and not in Java, but I would suppose that the same is possible if your IDE has become confused. Perhaps doing a clean up (making sure all the class files are gone) and a full rebuild might restore some sanity to your debugger. I would be wary about doing much with it if it is going to exhibit this kind of freaky behaviour.


  • Registered Users Posts: 4,666 ✭✭✭Imposter


    Originally posted by PhilH
    [I did some work ages ago where we occasionally saw the debugger point to comment lines and blank lines etc. It turned out that the debugger was pointing at compiled files that were not in synch with the source code, so when it was executing it thought it was on line 84 (say) of the file, but the file had changed and line 84 was now different. Admittedly this was in C++, and not in Java, but I would suppose that the same is possible if your IDE has become confused. Perhaps doing a clean up (making sure all the class files are gone) and a full rebuild might restore some sanity to your debugger. I would be wary about doing much with it if it is going to exhibit this kind of freaky behaviour.
    The debugger definitely wasn't out of synch. JBuilder will tell you that and stepping through the program it was obvious that it was clearly in synch.


  • Advertisement
  • Registered Users Posts: 21,264 ✭✭✭✭Hobbes


    == is for equating primatives. If statements can only equate to a boolean value as well (in C/C++ it is non-zero value afair).
    String a = "apple";
    String b = "apple";
    if (a == b)
    {
    System.out.println("Okay");
    }


    Should print out the word "Okay". The compiler should have decided it can re-use the object allocated to represent "apple" for both a and b.

    This is correct if the compiler is working that way. However if you were to do the following.
    String a = new String("apple");
    String b = new String("apple");
    if (a == b)
    {
    System.out.println("Not ok");
    }
    

    This would force the compiler to make different strings despite having the same value.

    So for comparing strings only uses the equals() or equalsIgnoreCase() methods on the String Class.

    Another thing to note is that "&&" is a short circuit AND. An example here would give a different value to 'i' depending on the value of 'b'.
    if (b == true && (i = i + 10) == 20) { 
        // i would be processed. 
    } else {
        // i would not be processed. 
    }
    

    Brackets would have no effect in this case as the first logical operation would dictate what else gets processed.


  • Closed Accounts Posts: 47 PhilH


    Hobbes mentioned (see his post)
    This is correct if the compiler is working that way.

    I think I am right in saying that if your compiler is not working that way, it is broken.

    I would however, completely agree with his assertion that testing string equality should always be done with the equals() method (or equalsIgnoreCase() if appropriate). I was merely trying to illustrate how come the use of the == operator might have resulted in the condition evaluating to true. It is very unwise however to rely on the specific situation where == happens to give the same result for String comparison, because that is almost certainly NOT what the programmer intends.

    The same caveat applies to other immutable value classes in Java, like Integer, Long (the wrapper objects), Date, Locale etc.


  • Registered Users Posts: 1,990 ✭✭✭lynchie


    Originally posted by bonkey
    Ok...firstly, if you check the actual source code in the string class for the .equals method, I think you'll see that it basically is implemented as :

    return a == b;

    In other words, a.equals(b) is synonymous with a == b : they do exactly the same thing.

    (I could be wrong...I don't have java source installed at the moment, so I'm working from memory).

    For all objects except those of type String equals(Object b) is implemented as a == b. But for strings it does a char by char comparison


  • Registered Users Posts: 4,666 ✭✭✭Imposter


    So what are we actually saying here other than == is not the correct way to do string comparisons?

    Is it that my if statement

    if(true && true) => false

    is a bug in the debugger and it should have been

    if(true && false) => false

    or something else?


  • Closed Accounts Posts: 47 PhilH


    Sorry, lynchie, I think you're wrong about that. The implementation for String does a char-by-char comparison, but it is not true to say that everything else does a reference comparison.

    Classes like Date, Locale, Integer, and a bunch of more complex ones like ArrayList act very differently from a simple reference check (the == operator).


  • Closed Accounts Posts: 47 PhilH


    Imposter,

    I'm at a loss with regard to your debugger's behaviour. I would completely agree with what you expect to see. Given that that's not what you're reporting, it has to come down to either a bug in the debugger (oh, the irony) or a mistake in observing the results. If you're happy that you're really witnessing the behaviour you're reporting, then I think you have to accept that there is something buggered about your debugger.


  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


    Originally posted by Imposter
    So what are we actually saying here other than == is not the correct way to do string comparisons?

    There's nothign wrong with using == for string comparison. I do it all the time, and it works exactly the way it should.

    Is it that my if statement

    if(true && true) => false

    is a bug in the debugger

    Well, thats not a java statement, so its not possible to answer that question.

    jc


  • Closed Accounts Posts: 47 PhilH


    bonkey's comment that
    There's nothign wrong with using == for string comparison.

    is a matter of opinion, and he's certainly entitled to it, but I think it would be hard to find a book on Java or an experienced practicioner who would agree with it (apologies to bonkey if he is an experienced practicioner, but if so, then I presume he knows he is in a minority with this opinion and is happy with that).


  • Registered Users Posts: 21,264 ✭✭✭✭Hobbes


    Originally posted by bonkey
    There's nothign wrong with using == for string comparison. I do it all the time, and it works exactly the way it should.

    In Java == should never be used for string comparison. A String is an object, not a primative.

    What JVM are you using?
    From jchq.net
    The difference between equals and == The equals method can be considered to perform a deep comparison of the value of an object, whereas the == operator performs a shallow comparison. The equals method compares what an object points to rather han the pointer itself (if we can admit that Java has pointers). This indirection may appear clear to C++ programmers but there is no direct comparison in Visual Basic.

    to prove this, create a string using the new String("."); method and then use == to try and compare.


  • Registered Users Posts: 678 ✭✭✭briano


    We were always taught to use the compareTo(String) or compareToIgnoreCase(String) operators from the String Class in if statements. But its probably not as efficient as the equals method.

    if(a.compareTo(b) == 0)
    {
    System.out.println("Good");
    }

    my 1/50th of any particular unit of currency.


  • Advertisement
  • Registered Users Posts: 4,666 ✭✭✭Imposter


    JDK-1.2.2_011

    I did a quick test. The debugger evaluated
    str1 == str2
    
    to true but the program goes into
    str1 != str2
    


  • Closed Accounts Posts: 99 ✭✭QBall


    Originally posted by bonkey
    There's nothign wrong with using == for string comparison. I do it all the time, and it works exactly the way it should.

    It may always work the way it "should" with your compiler.

    As I understand it, using == for string equality works if and only if the two references to the strings are equal. If your compiler always manages to store equal strings in the same place, causing the references to be the same then that's great.

    However, that doesn't work for all compilers (and to be honest I don't see how it could work with any decent speed for any compiler/JVM). Consider the following code:
    public class Test {
        public static void main(String args[]) {
            if (args[0] == args[1]) {
                System.out.println("==");
            } else {
                System.out.println("!=");
            }
    
            if (args[0].equals(args[1])) {
                System.out.println("equal");
            } else {
                System.out.println("!equal");
            }
        }
    }
    

    When I compile and run it, I get the following result:

    15:05 conor@mcdermc [~]> java Test foo foo
    !=
    equal

    The kit I'm using is:
    15:06 conor@mcdermc [~]> java -version
    java version "1.4.2-p6"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-p6-root_06_mar_2004_18_26)
    Java HotSpot(TM) Client VM (build 1.4.2-p6-root_06_mar_2004_18_26, mixed mode)

    What are you using? Are you really sure that it always works?


  • Registered Users Posts: 15,443 ✭✭✭✭bonkey


    This is where /me goes and pulls one of his java projects from cvs, looks at the code, and smacks himself in the forehead.

    Please ignore everything I've been saying, cause its complete ar5e.

    I've been coding c# so much this past year that I'm getting confused what is, and is not, common between them (and between how I code each of them).

    I don't use == for string comparison in Java. I do that in C#.

    I think I should go home now.

    jc


  • Registered Users Posts: 21,264 ✭✭✭✭Hobbes


    Originally posted by briano
    We were always taught to use the compareTo(String) or compareToIgnoreCase(String) operators from the String Class in if statements. But its probably not as efficient as the equals method.

    if(a.compareTo(b) == 0)
    {
    System.out.println("Good");
    }

    my 1/50th of any particular unit of currency.

    Your method will work but is a bit wasteful. If statements can only accept boolean as a result and equals() returns that, where as you are making two checks in that line to get the same answer.

    btw Someone said earlier that boolean is 1/0. That is wrong. boolean is true/false. the boolean cannot be used as a numeric value.


  • Closed Accounts Posts: 99 ✭✭QBall


    Originally posted by bonkey
    This is where /me goes and pulls one of his java projects from cvs, looks at the code, and smacks himself in the forehead.

    Please ignore everything I've been saying, cause its complete ar5e.

    I've been coding c# so much this past year that I'm getting confused what is, and is not, common between them (and between how I code each of them).

    I don't use == for string comparison in Java. I do that in C#.

    I think I should go home now.

    jc

    Don't worry about it. If I had a cent for every time I've used "eq" in Java after long Perl sessions I'd be pretty rich by now.

    :)


  • Registered Users Posts: 1,990 ✭✭✭lynchie


    Originally posted by PhilH
    Sorry, lynchie, I think you're wrong about that. The implementation for String does a char-by-char comparison, but it is not true to say that everything else does a reference comparison.

    Classes like Date, Locale, Integer, and a bunch of more complex ones like ArrayList act very differently from a simple reference check (the == operator).

    I was talking about class String's implementation of equals(), didnt mean to infer that all objects equals() method does a reference comparison :)


  • Closed Accounts Posts: 47 PhilH


    Here's a small point (we're getting down to the nitty gritty now).

    Using String's compareTo() methods is not quite the same as using equals(). If you have a String 's', and another object 'o' which is not a String, then

    if (s.equals(o))
    {
    // blah...
    }


    will work fine (the test will evaluate to false because 'o' is not a String). However the test

    if (s.compareTo(o))
    {
    // blah...
    }


    will give rise to a ClassCastException, because you can't sensibly compare a String to something that is not a String.

    It's a detailed point I know, but it does bring up a slightly more significant one. If a class has a method to do what you want (like equals in this case), you should be using it, not using something related because it sort of does the same thing (like compareTo). Whoever 'always taught' briano to use compareTo to check for equality should not be teaching.


  • Registered Users Posts: 1,931 ✭✭✭Zab


    Originally posted by QBall
    It may always work the way it "should" with your compiler.

    This actually isn't down to the compiler, it's down to the JVM. As already discussed, you generally cannot use == for a String comparison, as it compares two references, not two Strings. So when can you use ==?

    First up here is String's intern() method. This returns a canonical representation of the String. This means that it looks through its list of other intern()ed Strings, and sees if it has one that matches the String being interned. If it has one, it returns it. So, if we intern two strings we can use == to compare them, with correct results.

    For instance:
    String s1 = new String("hello");
    String s2 = new String("hello");		
    System.out.println("s1 == s2: " + (s1==s2));
    
    String in1 = s1.intern();
    String in2 = s2.intern();
    System.out.println("in1 == in2: " + (in1==in2));
    

    outputs
    s1 == s2: false
    in1 == in2: true
    

    Now, String literals and String constants are always interned, and this and the operation shown above are guaranteed by the JVM spec, not by the compiler. Even if the compiler decides to put equivalent string literals in different entries in the constant section of the .class file, the JVM will still use the same interned String to represent them.

    So why wouldn't you use interned Strings all the time? Well, there is obviously going to be a cost involved in interning the String in the first place, but more importantly the JVM spec doesn't specify that these strings have to be garbage collected, although modern Sun JVMs do seem to garbage collect interned strings. Generally, stick to the equals() method unless you have a good reason not too.


Advertisement