4

Following on from this question - how do you explain to someone that this is just crazy!:

boolean someMethod(Map<String, Object> context) {
 Object object = context.get("someProperty") 
 Object another = context.get("anotherProperty") 
 return object.toString().equals(another.toString());
}

Apparently the reason for why Object.equals(...) is not used is that "what's contained in the Map is not concretely known, but is definitely known to be one of the primitive wrappers i.e. String, Double, Boolean, etc... and that Boolean.TRUE is required to be equal(...) to the String "TRUE"".

asked May 17, 2012 at 9:38

4 Answers 4

7

It's wrong because there is no contract (not even an informal expectation!) for toString() that guarantees that any subclass of Object will define it in a way compatible with an equivalence relationship (read the javadoc for Object.equals() to see what I mean).

It may work for a class where you know that toString() is compatible with equals, but this is not the case for the values in Map<String, Object>!

For an obvious example where almost certainly the method doesn't do what you would expect, imagine a subclass of Object that does not override toString(). In that case, the String representation of your instance is a function of the class name and the object's hashCode. Almost certainly not what you want to use to test for equality.

answered May 17, 2012 at 12:25
19
  • Any comments on this part of the question? >> "what's contained in the Map is not concretely known, but is definitely known to be one of the intrinsic wrappers i.e. String, Double, Boolean, etc... and that Boolean.TRUE is required to be equal(...) to the String "TRUE"" Commented May 17, 2012 at 19:24
  • When in Rome, do as the Romans do: Java is a strong, static-typed language. Boolean.TRUE may be equal (IDK) to String "TRUE", but this is duck typing at hand and considered bad practice in Java. Also, what's guaranteed is that what's contained in the map is Object. Assuming otherwise is a bad idea, again because of the Java paradigms. Reminds me of "You can write Fortran in any language". Commented May 17, 2012 at 20:37
  • @loudsight What do you mean, "intrinsic wrappers"? In any case, String, Boolean and Double all have well-defined equal methods, which you might as well use (though I'm not sure it's numerically safe to use Double.equals(), but that's another issue). In the general case, toString() is not meant for equality tests, so don't use it for that. Commented May 17, 2012 at 22:32
  • Actually, I meant to say primitive rather than instrinsic. en.wikipedia.org/wiki/Primitive_wrapper_class Commented May 18, 2012 at 17:13
  • @loudsight Java primitive wrappers all have well-defined equals methods. You absolutely do NOT need to convert to String. Commented May 18, 2012 at 17:21
7

It's just crazy, because it can go wrong, because string representations are not canonical:

Double zeroDouble = new Double(0);
Integer zeroInteger = new Integer(0);
zeroDouble.doubleValue() == zeroInteger.doubleValue(); // true
zeroDouble.toString().equals(zeroInteger.toString()); // false ("0.0" vs "0")
File file1 = new File("file.txt");
File file2 = new File("FILE.TXT");
file1.equals(file2); // true in windows, false in unix
file1.toString().equals(file2); // false ("file.txt" vs. "FILE.TXT")
answered May 17, 2012 at 9:51
2
  • 1
    Actually, zeroDouble.equals(zeroInteger) is false. Commented May 17, 2012 at 10:36
  • Oops, I stand corrected. Numerical comparisons are almost never trivial :) Commented May 17, 2012 at 12:41
0

The indicated method would be very odd as part of a public API. Whether or not it is crazy as a private or protected part of a class would depend upon how it was being used. The method appears to encapsulate two different quirky aspects, either of which could plausibly be justifiable in some contexts but not others; while it would seem unlikely that both would be justifiable, there's no particular reason why they couldn't be.

The first quirky aspect is the fact that the method is searching for particular fixed strings within the maps. Such behavior is generally ugly (and it would probably be better if the strings were defined as constants) but could be justifiable if:

  1. The map is never exposed to code outside the package.
  2. It is necessary to use some collection type to store aggregates, each of which consists of a mapping plus a few other bits of information).
  3. The use of the encapsulated mapping is such that no key could possibly conflict with the strings that are used for the "few other bits of information".
  4. The mapping is used so much more than the other bits of information stored within the advocate that using a class which contained a Map along with the other bits of information would be much more cumbersome than using a map which has a few bits of information associated with magic keys.

Some languages and frameworks would provide alternate means of attaching supplemental information to a type, but the approach indicated here is sometimes the most practical one given Java's type system.

The second ugly aspect is that the code is comparing two objects' ToString values as a means of comparing the objects. In most cases, either the objects will be strings (in which case one could just compare them), or they would be some other type which has some attribute of type String such a name, in which case one should cast the objects to that other type, call GetName on both instances, and compare the resulting strings. If, however, the majority of table entries would only need to store strings, but a few might need to have an entry which combines a string with a small amount of supplemental information, it may in some cases be easier to store things in the table as type Object with the expectation that every entry will either be a String, or be some known kind of object. Since Java's type system has no concept of "thing which will either be type1 or type2", using Object, though ugly, may be the only practical alternative in cases where one of the types is something like String which would share no common ancestor--other than Object--with any user class.

answered Oct 24, 2014 at 17:50
-6

If you are keenly interested to know about Object Equality then use can use the method of class Object.

int hashCode() gives the integer value called hashCode which pertain to an object.

definitely the hashcode differs object to object.
 it's a easiest way to identify object equality.
answered May 17, 2012 at 15:36
2
  • There is no guarantee that equal objects have the same hashcode, and similarly there is no guarantee that non-equal objects have differing hashcodes. Commented May 17, 2012 at 16:28
  • 2
    This is a serious misunderstanding of what hashCode does. Commented May 17, 2012 at 21:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.