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"".


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.

  • 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"" – auser May 17 '12 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". – K.Steff May 17 '12 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. – Andres F. May 17 '12 at 22:32
  • Actually, I meant to say primitive rather than instrinsic. en.wikipedia.org/wiki/Primitive_wrapper_class – auser May 18 '12 at 17:13
  • @loudsight Java primitive wrappers all have well-defined equals methods. You absolutely do NOT need to convert to String. – Andres F. May 18 '12 at 17:21

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")
  • 1
    Actually, zeroDouble.equals(zeroInteger) is false. – waxwing May 17 '12 at 10:36
  • Oops, I stand corrected. Numerical comparisons are almost never trivial :) – Joonas Pulakka May 17 '12 at 12:41

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.


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.
  • There is no guarantee that equal objects have the same hashcode, and similarly there is no guarantee that non-equal objects have differing hashcodes. – RonU May 17 '12 at 16:28
  • 2
    This is a serious misunderstanding of what hashCode does. – Andres F. May 17 '12 at 21:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.