Java Forum / General / August 2006
noob question: string comparing
user - 31 Jul 2006 07:18 GMT if i want to compare a string str to something like... the letter f, what do i do? (str == "f") seems to return false everytime.
Lars Enderin - 31 Jul 2006 09:22 GMT user skrev:
> if i want to compare a string str to something like... the letter f, > what do i do? > (str == "f") seems to return false everytime. The == operator compares String pointers, not values. Use "f".equals(str). The comparison order avoids null references.
Tim Ward - 31 Jul 2006 09:48 GMT > user skrev: > > if i want to compare a string str to something like... the letter f, [quoted text clipped - 3 lines] > The == operator compares String pointers, not values. Use > "f".equals(str). The comparison order avoids null references. And ... for an encore ... the "byte" data type is signed!!
(There are a number of completely mad design decisions in the Java language but these two have got to be the worst ... unless anyone can come up with any even more ludicrous examples? There's constructors calling virtual methods on partially-constructed objects, of course, but that one tends to bite people later on.)
-- Tim Ward Brett Ward Limited - www.brettward.co.uk
Eric Sosman - 31 Jul 2006 13:13 GMT >>user skrev: >> [quoted text clipped - 9 lines] > (There are a number of completely mad design decisions in the Java language > but these two have got to be the worst ... The signedness of `byte' is unfortunate, and is possibly a product of the hobgoblin of little minds. But keeping the notions of `==' and `.equals()' separate is another matter; if you consider it "mad" I suspect you haven't thought about it enough. ("People go mad if they think too much.")
 Signature Eric Sosman esosman@acm-dot-org.invalid
Ian Wilson - 15 Aug 2006 09:55 GMT >>> user skrev: >>> [quoted text clipped - 16 lines] > you consider it "mad" I suspect you haven't thought about it > enough. ("People go mad if they think too much.") Keeping the notions of "equal value" and "refer to same object" separate is good. But I sometimes wonder if the operators could have been allocated in such a way as to cause least confusion to learners.
e.g. == for the extremely commonly meant 'has same string value as' and .sameObject() for the far less used 'are both references to the same thing'.
Eric Sosman - 15 Aug 2006 15:33 GMT Ian Wilson wrote On 08/15/06 04:55,:
>> The signedness of `byte' is unfortunate, and is possibly >>a product of the hobgoblin of little minds. But keeping the [quoted text clipped - 8 lines] > e.g. == for the extremely commonly meant 'has same string value as' and > .sameObject() for the far less used 'are both references to the same thing'. How would you test for a null reference in this scheme?
someString.equals(null) // NPE if someString is null null.equals(someString) // doesn't compile ((String)null).equals(someString) // NPE always
I guess the test *could* be made:
static boolean isReferenceNull(Object ref) { try { ref.getClass(); // NPE if ref is null return false; // no NPE -> not null } catch (NullPointerException ex) { return true; // only one way to get here } }
... but this is vile.
 Signature Eric.Sosman@sun.com
Oliver Wong - 15 Aug 2006 15:36 GMT > Ian Wilson wrote On 08/15/06 04:55,: >>> [quoted text clipped - 31 lines] > > ... but this is vile. Also the compiler cannot determine whether two objects have semantically "equal value", and so the programmer would have to provide code, which would force the addition of operator overloading (to overload the == operator).
- Oliver
David Segall - 31 Jul 2006 15:36 GMT >if i want to compare a string str to something like... the letter f, >what do i do? >(str == "f") seems to return false everytime. I have found it a very difficult lesson to learn but == in Java does not have the same meaning as equals in other languages. If you want to test for equality you need to use the equals method of the object str so you need to test as follows: if (str.equals"f") {... or, God forbid, if ("f".equals(str)) {...
It seems that origin of this is that it is much easier, when writing an interpreter that is meant to work in a tiny "set top box" computer, to test for equality between two pointers to an object than to test if a human interpretation of the two objects are equal. Consequently, unless the arguments are primitive types, == just checks to see if the two arguments are the same object.
Eric Sosman - 31 Jul 2006 16:07 GMT David Segall wrote On 07/31/06 10:36,:
>>if i want to compare a string str to something like... the letter f, >>what do i do? [quoted text clipped - 14 lines] > unless the arguments are primitive types, == just checks to see if the > two arguments are the same object. It's not a matter of easier or harder, but of modelling the real world satisfactorily. The real world presents us with multiple different notions of "equality," two of which are supported by Java:
- Identity: Two objects A and B are "equal" if they are in fact the same object under different names. "David" and "Mr. Segall" refer to the same object (granting a suitable universe of discourse), so they are equal. This is the "equality" Java's == operator tests.
- Equivalence: Two objects A and B are "equal" if they are of the same class and have the same "value." This bottle of Pirelli's Miracle Elixir contains 100 ml. of that efficacious fluid, that other bottle holds the same amount of the same stuff, so the two bottles are "equal" in the sense of being equivalent. This is the notion the equals() method tests (depending, of course, on how the class defines the method).
If you are having trouble separating these two notions, consider your wallet for a moment. By pure coincidence, it happens to contain the same amount of money as my wallet. The two wallets are therefore equal in purchasing power; does that mean they are the same wallet? If so, hand over your wallet immediately: it's mine!
 Signature Eric.Sosman@sun.com
David Segall - 31 Jul 2006 17:17 GMT >David Segall wrote On 07/31/06 10:36,: >> [quoted text clipped - 29 lines] >that mean they are the same wallet? If so, hand over your >wallet immediately: it's mine! I don't dispute your two concepts of equality but you have used sleight of hand to claim my wallet. I have no objection to being forced to explicitly compare wallet.colour, wallet.size etc in addition to wallet.value to protect my wallet. Java confuses beginners because it assigns a default property (.value) to a String object in the equals() method but omits that property and insists on using the unfamiliar concept of "identity" with the == operator. This contrasts with most (all?) other languages which is why I concluded that it was done for the benefit of the interpreter programmer rather than the application programmer.
Oliver Wong - 31 Jul 2006 18:00 GMT >> The real world presents us >>with multiple different notions of "equality," two of which [quoted text clipped - 26 lines] > forced to explicitly compare wallet.colour, wallet.size etc in > addition to wallet.value to protect my wallet. I don't think the wallet is the greatest example, but you could imagine that your wallet and Eric's wallet are identical in every respect (colour, number of protons, electrons and neutrons that compose it, etc.), but the two wallets are still distinct.
Maybe this example will be better:
Alice and Bob are speaking:
Alice: "I'm thinking of a specific friend." Bob: "I too am thinking of a specific friend." Alice: "My friend is 28 years old." Bob: "My friend is also 28 years old." Alice: "My friend has brown eyes, blond hair." Bob: "Mine too." Alice: "My friend's name is Charlie." Bob: "So is mine!" [etc. This goes on, Alice listing a whole bunch of attributes about her friend, and Bob saying those same attributes apply to his friend.]
So, are Alice and Bob thinking about the same person? It might be, or it might not be. It's possible that they are speaking about two completely different people who are remarkably similar, or it might be that they are in fact speaking about the exact same person, not knowing that they had a common friend.
Alice: "Well, my friend Charlie's cell phone number is 12345678901." Bob: "Oh, well I don't know what my Charlie's cell phone number is. However, his house number is 19876543210." Alice: "Hmm, I don't know what my friend's Charlie's home number is."
Just like a person can have multiple phone numbers, so can objects in Java have multiple references pointing to them. The fact that you have two different references doesn't nescessarily mean you have two different objects!
Alice: "Well, my friend Charlie lives alone at 22 Baker Street." Bob: "Ah, so does mine. So we must be talking about the same person."
One way to think of it is that references are sort of like pointers which hold the address of the objects they are refering to. When you use the == operator on two reference, it's comparing the addresses that each reference points to, to see if they are identical. When you invoke the .equals() method, you're invoking it on a specific object, and that method is free to do anything the programmer designed it to do. In fact, it can even "lie" to you and return false when you check if an object is equal to itself, or it can be programmed to erase all the files on your haddrive, etc.
Usually, you assume that the programmer who wrote the equals is not malicious, and you can just read the documentation for the equals() method to find out exactly how it determines equality between two objects, or failing that, read the source code itself.
> Java confuses beginners > because it assigns a default property (.value) to a String object in > the equals() method but omits that property and insists on using the > unfamiliar concept of "identity" with the == operator. I think this "assigning a default property (.value) to a String object" explanation may be very misleading. The JVM never creates fields out of nowhere. If a object has a field, it's because the class that defines that object declared the field. If you look at the source code for the String class, it actually has 4 fields:
private final char value[]; private final int offset; private final int count; private int hash;
If you check the source code for the equals() method in String, you'll see it essentially does a character-by-character scan from value[offset] to value[offset + count - 1] to check if two string objects are equal. So it's possible that two String object have completely different field values, but are evaluated to be equal! For example if the two String's field values are:
StringOne { value[] = {'A', 'B', 'C', '1', '2', '3'} offset = 3; count = 3; hash = 42; }
and
StringTwo { value[] {'1', '2', '3', 'X', 'Y', 'Z'} offset = 0; count = 3; hash = 69; }
StringOne.equals(StringTwo) would return true, because of the way it's programmed.
> This contrasts > with most (all?) other languages which is why I concluded that it was > done for the benefit of the interpreter programmer rather than the > application programmer. I think what you were missing was the fact that the .equals() method can be programmed to do anything the programmer wishes.
- Oliver
Eric Sosman - 31 Jul 2006 18:28 GMT David Segall wrote On 07/31/06 12:20,:
> [...] > I don't dispute your two concepts of equality but you have used > sleight of hand to claim my wallet. Sleight of hand, prestidigitation, trickery and ruses, scams and frauds -- if I can grab other peoples' wallets, it's all worth while! ;-)
> I have no objection to being > forced to explicitly compare wallet.colour, wallet.size etc in > addition to wallet.value to protect my wallet. Java confuses beginners > because it assigns a default property (.value) to a String object in > the equals() method but omits that property and insists on using the > unfamiliar concept of "identity" with the == operator. I'm not at all sure what you mean by a "default" property. The String.equals() method makes a computation, just as other equals() methods -- other anything() methods -- make their computations. String.equals() takes one set of things into account; BigInteger.equals() computes things differently; neither seems (to me) to "default" to anything.
> This contrasts > with most (all?) other languages Here I must disagree, although it's risky: I've used only a couple dozen programming languages, well short of "most." But among those I've used that support the notion of "reference" as a first-class value, I cannot think of any that make Java seem at all unusual in this regard. All of them made a clear distinction between the reference and the thing referred to.
In C, consider
char *p = "Hello, world!"; char *q = malloc(strlen(p) + 1); /* assume success */ strcpy (q, p);
This fragment points p at a character string, then points q at an exact copy of that string. At this point p and q are not == because they point to different string instances, yet strcmp(p, q) reports that the strings compare equal. This should seem eerily similar to Java's behavior with
String p = "Hello, world!"; String q = new String(p);
And if you find two notions of "equality" confusing, it's a good thing you never encountered Lisp! My Lisp days are far behind me and my memory of them has gone a bit foggy, but I recall that Common Lisp supports at least four different notions of equality, maybe five.
> which is why I concluded that it was > done for the benefit of the interpreter programmer rather than the > application programmer. I don't think the conclusion follows from the premise.
 Signature Eric.Sosman@sun.com
dsjoblom@abo.fi - 31 Jul 2006 18:11 GMT > It seems that origin of this is that it is much easier, when writing > an interpreter that is meant to work in a tiny "set top box" computer, > to test for equality between two pointers to an object than to test if > a human interpretation of the two objects are equal. Consequently, > unless the arguments are primitive types, == just checks to see if the > two arguments are the same object. Which also happens to be the case with pointers in C. And since java borrows heavily on syntax (and some semantics) from C, and java references are essentially pointers, the function of == is not that surprising, and has nothing to do with ease of implementation. I might also add that if the == operator didn't do what it currently does, we would need some other way of checking reference equality.
Regards, Daniel Sjöblom
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|