Thoughts on a new method for equality on java.util.Objects?

David Alayachew davidalayachew at gmail.com
Sun Feb 11 05:16:29 UTC 2024


Hello Core Libs Dev Team,

I jumped the gun a bit and made a PR for this first. Alan Bateman kindly
informed me of my faux pas, and now I'm trying to redo things correctly.

I am looking to add a new method to java.util.Objects to facilitate
equality checks, something that I hope fits well in place with the other
methods in this class.

Here is my basic idea. (Special thanks to @liach for guidance in creating
this!)

```java
import java.util.*;
import java.util.function.*;

import static java.util.Objects.*;

public class Objects2
{

   public static <T> BiPredicate<T, T> equalsBy(final List<Function<T, ?>>
functions)
   {

      requireNonNull(functions, "Objects.equalsBy cannot execute because
the parameter is null!");

      return
         (final T o1, final T o2) ->
         {

            requireNonNull(o1, "Cannot check for equality because the first
object is null!");
            requireNonNull(o2, "Cannot check for equality because the
second object is null!");

            for (final var function : functions)
            {

               requireNonNull(function, "Cannot check for equality because
the function is null!");

               final var r1 = function.apply(o1);
               final var r2 = function.apply(o2);

               final boolean theyAreEqual = Objects.equals(r1, r2);

               if (!theyAreEqual)
               {

                  return false;

               }

            }

            return true;

         }
         ;

   }

   public static void main(final String[] args)
   {

      record Point3D(int x, String y, int z) {}

      final Point3D a = new Point3D(1, "2", 3);
      final Point3D b = new Point3D(1, "2", 4);

      final BiPredicate<Point3D,Point3D> equalsByXY  =
equalsBy(List.of(Point3D::x, Point3D::y));
      final BiPredicate<Point3D,Point3D> equalsByXYZ =
equalsBy(List.of(Point3D::x, Point3D::y, Point3D::z));

      System.out.println(equalsByXY.test(a, b));  //true
      System.out.println(equalsByXYZ.test(a, b)); //false

   }

}
```

The concept is simple -- I want to make it easy to create ad-hoc equals
methods.

Object equality is domain-specific -- in some domains, 2 objects are equal,
but in another, they are not. The object's equals method is not always a
good spot to put this logic into, largely because we don't always know what
domain we are in. The object's equals method is where a good default should
be placed, not logic for every domain. And even if we tried, it's
difficult, if not impossible, to apply equality for the correct domain if
both objects are of the same type.

So, for domain-specific contexts, I would like to introduce this method.
This method (which should be constant-foldable, thanks again for the help
@liach!) lets you clearly say that you are taking 2 objects and comparing
them by the following methods that apply to both. And due to the nature of
lambdas, developers are not constrained to just the getters of the object
in question -- any function that takes in T is fair game. This allows
flexibility, and lets developers keep their objects simple, thus
facilitating things like DOP.

Now, perhaps this makes more sense on the BiPredicate interface instead.
However, since this was more equality focused, I figured Objects was a
better fit.

Any thoughts?

Thank you all for your time and help!
David Alayachew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240211/c29926ab/attachment-0001.htm>


More information about the core-libs-dev mailing list