0

I am wondering whether it is possible to add something like Objects.equals() that allows runtime checking of types.
Note: I know, that is not what you always want to do, but I think it has its use cases. At least for me.

Example problem: I have some class, let's say, an id of type Integer. And I have an entity Foo with foo.getId() returns a type Integer. For some reasons I check for equality with Objects.equals(someId, foo.getId()).
Now I refactor my entity, foo.getId() will no longer return an Integer but will return Long. Unfortunatelly, there will be no compile time hint at all that Objects.equals(someId, foo.getId()) will never return true. (Yes, stuff like sonarqube helps you a bit).

To solve that, I thought I write something like

private static <T> boolean equals(T object1, T object2) {
    return Objects.equals(object1, object2);
}

which.....just does not work. It still accepts any arbitrary Object. Is there any possible solution in Java for this?

Edit: Please note, this question has nothing to do with equals and hashCode of an object or overriding equals of an object in general, I am looking for a compile-time solution.

markus_
  • 480
  • 3
  • 12
  • I don't know about compile error or code solutions, but Eclipse for example has an option for Errors/Warnings called "Unlikely argument type for method equals()" where you can configure if it should ignore, inform or even show an error for that Problem. For example, when activated it will display the Error `"Unlikely argument type for equals(): Long seems to be unrelated to Integer"` for `Objects.equals(Integer.valueOf(1), Long.valueOf(1))`. So maybe whatever IDE you are using has something similar and you can handle it with that. – OH GOD SPIDERS Dec 09 '22 at 12:39
  • Have you considered `instanceof`, `Class#isInstance`, `Class#isAssignableTo`, and comparing the class types via `==`? – Rogue Dec 09 '22 at 12:40
  • Does this answer your question? [What issues should be considered when overriding equals and hashCode in Java?](https://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java) – Torben Dec 09 '22 at 12:52
  • @OHGODSPIDERS yes my IDEs does that, but compiling still works – markus_ Dec 09 '22 at 13:02
  • @Rogue that's not compile time, sorry – markus_ Dec 09 '22 at 13:02
  • @user16320675 yes, that is what I have done so far and it has the drawback you mentioned, I had to write `MyClass.equals` – markus_ Dec 09 '22 at 13:04
  • @Torben your propsed answer is only very loosely coupled to my question, sorry... – markus_ Dec 09 '22 at 13:05

2 Answers2

0

I think there is no fast solution short of writing a bunch of equals() methods. This might be feasible if you have only a limited set of types that you want to use:

public class Equals {

    public static boolean equals(Integer a, Integer b) {
        return Objects.equals(a, b);
    }

    public static boolean equals(Long a, Long b) {
        return Objects.equals(a, b);
    }

    public static void main(String[] args) {
        // System.out.println(equals(1, 1L)); doesn't compile
        System.out.println(equals(1, 1));
        System.out.println(equals(1L, 1L));
    }
}
Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34
  • It's not what i wanted :D and I will definitely NOT write dozens of equals methods...but it supports my feeling that there just isn't any solution for what I want thus I will accept this. Thank you for your reply – markus_ Dec 12 '22 at 09:35
0

Just as Thomas already mentioned, I cannot think of a fast solution either.

You have several options, some of which you may have already tried:

  • You may use your own equals methods, forcing you to pass two arguments of the same type (either both Integer or both Long). This is the solution Thomas proposed.

  • You may force a certain type by typecasts:

    Objects.equals((Integer) someId, (Integer) foo.getId())
    

    The compiler starts whining if you change the type of either of the arguments.

  • Apply encapsulation. Create a class Id, in which you store the actual value, either as a Long or as an Integer. Then if you return an id anywhere, use the Id class for it. The problem with directly using a Long or Integer is that you expose the internal implementation. And when you change the implementation, you change the interface.

    Whether this option is feasible, depends on your use case.

If you don't want to use a class Id, then I suggest you switch to Long, and hope you don't ever need an id greater than 9,223,372,036,854,775,807.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • Thank you. While encapsulation in general is a good idea it does not help with the problem. It is still an Object and thus viable for the equals-method without any compiler warning. – markus_ Dec 12 '22 at 09:33