简体   繁体   中英

Java HashMap key comparison against string fails

I have the following situation. I have a HashMap in Java with keys as strings. Then in some stage , in runtime I create strings equal to those keys in order to retrieve the data from that map.The strings are created as follows within "for" loop:

 String keyToRetrive = "lights[" + Integer.toString(i) + "]" + ".Intensity";

The strange thing about it that when I iterate through the map to find the key that equals that string ,even when the match is found the search steps over.So in this search loop :

  while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        if (name == entry.getKey()) {  ///name- "lights[0].Intesity"
            uniformOut = (ICleanable) entry.getValue();
            break;
        }
    }

The key with the name "lights[0].Intesity" never returns true even that the map contains one.How I solved it .I used hashCode() for both compared string values.So this version does work:

 while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        if (name.hashCode() == entry.getKey().hashCode()) {
            uniformOut = (ICleanable) entry.getValue();
            break;
        }
    }

UPDATE: After being pointed to the fact that "==" doesn't work good and "equals()" should be used I would like to narrow the question:Why "==" does work for strings which were not created from several concatenated blocks? I mean, if I defines key string to compare agains as a simple single string:

 String foo="foo";

Such a string is compared using "==" against HashMap key all right.

I am not an expert Java programmer so can anybody explain why it works this way?

You are comparing Strings using == operator. Use equals() instead:

name.equals(entry.getKey())

This is a common pitfall in Java, see How do I compare strings in Java? and Difference between Equals/equals and == operator? .


BTW (unrelated to your problem) when concatenating strings you don't need to call toString() explicitly so this:

"lights[" + Integer.toString(i) + "]" + ".Intensity"

can be replaced with:

"lights[" + i + "]" + ".Intensity"

It'll work for i of any type, not only int .

When you compare objects using == , you're performing a "referential equality" comparison, meaning that you're checking whether the two references point at the same String object in memory . If you're familiar with C, it would be like:

char* a = some_string();
char* b = some_other_string();
if (a == b) { ... }

On the other hand, when you compare objects using .equals() , you're performing a "structural equality" comparison, meaning that you're checking whether the two objects contain equivalent data. Again, the C analog of this would be:

char* a = some_string();
char* b = some_other_string();
if (strcmp(a, b) == 0) { ... }

Now, the thing you really, really don't want to do is to compare the two objects' hash codes. Why not? Because two objects with the same hash code are not necessarily equal! They might be, but you can't correctly rely on it.


Update: You also asked about why == works for string literals. The answer is because the Java compiler doesn't allocate constant strings on the heap; instead it stores them in the constant pool of the class in which they're used. So, if you write:

String foo1 = "foo";
String foo2 = "foo";

Then the compiler will have both references point at the same location in the class's constant pool. If, however, you write:

String foobar1 = "foobar";
String foobar2 = "foo" + bar();
String bar() { return "bar"; }

The compiler isn't quite smart enough to figure out that foobar2 is logically equivalent to foobar1 . However, even if you know that the two variables are compile-time constants, you still should keep it simple and use .equals() .

The others have stated why your code won't work, however:

1) If you're using a HashMap, you should use map.get(key) to retreive the value, not an interator of entries; that's the whole point of the Hash Map.

2) Use generics, avoid explicitly casting as much as you can!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM