2

To me, equals() between objects of inconvertible types is one of the most useful IntelliJ inspection. It's almost never intended to have objects with different types equal to each other.

I understand equals method was introduced prior to Java 5 so there is no generics to leverage. But even the new null safe Objects.equals introduced by JDK7 is still not type safe. Am I missing some key consideration of this design?

By typesafe equals(), I mean something like public static <T> boolean equals(T a, T b). So that it becomes a compilation error rather then inspection warning.

====================================

added on 2018-11-17:

RE: user949300's answer. I understand there will be uncovered edge cases when we use a more restricted version of equals. But in reality, most of the case by calling equals we are really just comparing DTOs: are they having the same type and do they have the same properties? I am not suggesting we should always use the restricted version but it should help in 95% of the case as compiler can make things more obvious than IDE specific inspector.

  • Won’t the generic version infer T to be Object on mismatch, since everything in Java can be convertible to Object? – Telastyn Nov 13 '18 at 15:34
  • Not sure I understand what you mean. Can you share an example? – Max Nov 13 '18 at 15:37
  • foo.Equals(bar) since foo and bar necessarily inherit from Object, the generic function infers Object to be T. – Telastyn Nov 13 '18 at 16:06
7

Ignoring the erasure issues mentioned in the comments, there are other issues with equals that might make a general "type safe" implementation problematic. The main one is how to test for the compatibility of your type T. Let's say you have a class Foo and a subclass SpecialFoo.

You propose this: public static <T> boolean equals(T a, T b)

The classic question is, does T have to be an exact match? In other words, if a is a Foo, and b is a SpecialFoo, can they be equal?

The answer is, "it depends", and is domain specific. You'll see religious wars online about this.

For example, you'll see two different ways to test type compatibility in the typical public boolean equals(Object other) method.

  • some use this.getClass() == other.getClass(), exact match
  • some use other instanceof Foo subclasses are o.k.

I recommend you check out Effective Java for more extensive discussion.

  • I understand there will be uncovered edge cases when we use a more restricted version of equals. But in reality, most of the case by calling equals we are really just comparing DTOs: are they having the same type and do they have the same properties? I am not suggesting we should always use the restricted version but it should help in 95% of the case as compiler can make things more obvious than IDE specific inspector. – Max Nov 17 '18 at 10:14
  • In that case, it is IntelliJ that needs to be smarter when applying the inspection. In other words, IntelliJ can look at the equals() implementation, and deduce what argument types would be accepted by the method. (Java has a presumption against changing the language or compatibility. Anything that can be done by tools are excluded from the responsibility of the language.) – rwong Nov 17 '18 at 10:43

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.