12

How can I bind a Java Supplier to an existing instance of an Object? For example, if I want to write my own compareTo() method with this header:

public static int myCompareTo(Object o1, Object o2, Supplier<Comparable> supplier) {...}

I want be able to call it like:

myCompareTo("Hello", "Hello2", String::length);

where String (with the capital letter) is a class and no object. So how can I bind the instance o1 to the supplier?

0xCursor
  • 2,242
  • 4
  • 15
  • 33

4 Answers4

4

Here's what you were searching for (I believe):

public static <T, U extends Comparable<U>> int compare(T o1, T o2, Function<T, U> mapper) {
    return mapper.apply(o1).compareTo(mapper.apply(o2));
}

You can call that like so:

compare("str1", "str2", String::length); // 0
steffen
  • 16,138
  • 4
  • 42
  • 81
4

Thanks for your answers. Actually I figured it out now. I wanted to have the supplied object instances (o1 and o2) to execute the given method. I found out that Supplier was the wrong interface instead I had to use Function. Here you can see my working simplified example:

public static <T> int myCompareTo(T o1, T o2, Function<T, Comparable> getter) {
        return getter.apply(o1).compareTo(getter.apply(o2));
}

The reason, the interface has to be Function and not Supplier is, that only Function is equivalent to a lambda expression taking an object and calls the referenced method on the object.

For example, if you define the method reference as:

Function<TypeOfInstance, ReturnTypeOfReferencedMethod> methodReference = TypeOfInstance::referencedMethod();

then the equivalent lambda expression being executed is:

(instance) -> instance.referencedMethod()

Additional Information:

Edit: I know I could have done the same by using Comparator, but this example is very simplified. In my application a Function of this kind is neccessary. I had to create a compareTo function that sorts an ArrayList by more than one attribute because the main sorting attribute may not be unique in the list. I want to share my code with you, because I think it can be a interesting insight for you.

public static <T> int ultimateCompare(T o1, T o2, Function<T, Comparable>... getters) {
    for (Function<T, Comparable> getter : getters) {
        int result = getter.apply(o1).compareTo(getter.apply(o2));
        if (result != 0) return result;
    }
    return 0;
}

With this for example, you can sort a list of persons by last name and if two of them are identical, you can use the first name to sort. With this solution you can change sorting at runtime.

3

Actually a more correct way to define your method would be:

private static <T, U extends Comparable<? super U>> int myCompareTo(T left, T right, Function<T, U> fu) {
    return Comparator.comparing(fu).compare(left, right);
}
Eugene
  • 117,005
  • 15
  • 201
  • 306
1

You can use

Comparator.comparing(String::length);

to obtain a comparator instance which you can pass to the method.

senjin.hajrulahovic
  • 2,961
  • 2
  • 17
  • 32