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?
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
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.
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);
}
You can use
Comparator.comparing(String::length);
to obtain a comparator instance which you can pass to the method.
Related
The Function interface has the compose() and andThen() methods while the BiFunction interface only has the andThen() method. My question is simply how could the corresponding method be implemented? I'll try to represent this graphically.
The single letters are parameterized types as defined by Java's Function and BiFunction interfaces. Arrows are the flow of inputs and outputs. Boxes with connected arrows are functions. The dotted box just shows how the apply method is used.
The Function's Compose() and andThen() methods are straightforward since a Function has one input and one output and therefore can only be strung sequentially with another in two ways.
Since a BiFunction has one output, the "after" function has to be something with only one corresponding input, and Function fits the bill. And since it has two inputs, the "before" function needs to be something with two outputs? You can't have a method return two things, so there seemingly can't be a "before". The return type of each of these methods is the same as the interface they are defined in, so the proposed method should return a BiFunction.
My proposal then is a method that takes two Functions as input and returns a BiFunction. I'm not sure what else it could even be. It couldn't be two BiFunctions because then the return type would have to be a QuaterFunction.
Here is the code as it would be written in the Java Library:
public interface BiFunction<T, U, R> {
// apply()...
default <V, W> BiFunction<V, W, R> compose(
Function<? super V, ? extends T> beforeLeft,
Function<? super W, ? extends U> beforeRight) {
Objects.requireNonNull(beforeLeft);
Objects.requireNonNull(beforeRight);
return (V v, W w) -> apply(beforeLeft.apply(v), beforeRight.apply(w));
}
// andThen()...
}
Here is the finished graph:
Here it is in use:
BiFunction<Integer, Integer, Integer> add = Integer::sum;
Function<Integer, Integer> abs = Math::abs;
BiFunction<Integer, Integer, Integer> addAbs = add.compose(abs, abs);
System.out.println(addAbs.apply(-2, -3));
// output: 5
If you want to actually test this, you can do something like this:
public interface BiFunctionWithCompose<T, U, R> extends BiFunction<T, U, R> {...
Or like this:
package myutil;
public interface BiFunction<T, U, R> extends java.util.function.BiFunction<T, U, R> {...
I have no idea if this will be useful to anyone, but it was really fun to think through and write. Have a wonderful day.
I'm trying to make sense of how Comparator.comparing function works. I created my own comparing method to understand it.
private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
return (Comparator<T>) bfun;
}
The last line in this function throws an exception.
However, if I change this function to
private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
return (T a, T b) -> f.apply(a).compareTo(f.apply(b));
}
It works just fine as expected.
What is the intermediate functional interface which the second attempt uses, which is able to convert the lambda to Comparator?
What is the intermediate functional interface which the second attempt uses, which is able to convert the lambda to Comparator?
The Comparator itself.
Within the second method, you have defined a Comparator, not an intermediate object that has been cast to the Comparator.
The last line in this function throws an exception.
Yes, it should.
If two classes are functional interfaces and have similar methods (with the identical signatures and the same return type), it doesn't mean that they can be used interchangeably.
An interesting trick - you may make a Comparator<T> by referring to the BiFunction<T, T, Integer> bfun's method apply:
private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
final BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
return bfun::apply; // (a, b) -> bfun.apply(a, b);
}
The intermediate functional interface in your second attempt is simply Comparator<T>:
You can see this because your code-snippet is equivalent to the following:
private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
Comparator<T> comparator = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
return comparator;
}
I'm little confused about how the generics works? I'm learning about function API in java and there I just test Function interface and got confused about compose method that how the generics is working in compose method.
Reading the generics on the java official tutorial website I realize that if we have any generic type in the method return or parameters we have to declare that type in the signature of method as explained below.
Here is the method I read in official docs tutorial.
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
Above method have two types, K, V which are declared in the signature after the static keyword as but when I read java Function API there is one method called compose and the signature of the compose is as
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
1) The first question where is the T & R declared? which are being used in the return type and in the parameter. Or my understanding is wrong?
Then I read more in generics tutorials and then I try to understand the concept of super and extends in generics and read here then I test compose method more and then confused again about how the super and extends works in the compose method?
public static void main(String... args){
Function<Integer, String> one = (i) -> i.toString();
Function<String, Integer> two = (i) -> Integer.parseInt(i);
one.compose(two);
}
As above I have declared two Function with lamdas. One is having Integer input and String output the other one is reversed from it.
2) The second question is that how Integer and String are related to extends and super? There is no relation between String and Integer class no one is extending each other then how it is working?
I tried my best to explain my question/problem. Let me know what you didn't understand I will try again.
Where are T and R defined?
Remember, compose is declared in the Function interface. It can not only use generic parameters of its own, but also the type's generic parameters. R and T are declared in the interface declaration:
interface Function<T, R> {
...
}
What are ? extends and ? super?
? is wildcard. It means that the generic parameter can be anything. extends and super give constraints to the wildcard. ? super V means that whatever ? is, it must be a superclass of V or V itself. ? extends T means that whatever ? is, it must be a subclass of T or T itself.
Now let's look at this:
Function<Integer, String> one = (i) -> i.toString();
Function<String, Integer> two = (i) -> Integer.parseInt(i);
one.compose(two);
From this, we can deduce that T is Integer and R is String. What is V? V must be some type such that the constraints Function<? super V, ? extends T> is satisfied.
We can do this by substituting the argument we passed in - Function<String, Integer> - to get String super V and Integer extends Integer.
The second constraint is satisfied already while the first constraint now says that String must be a super class of V or String itself. String cannot have subclasses so V must be String.
Hence, you can write something like:
Function<String, String> f = one.compose(two);
but not
Function<Integer, String> f = one.compose(two);
When you compose a Function<Integer, String> and a Function<String, Integer> you cannot possibly get a Function<Integer, String>. If you try to do this, V is automatically inferred to be Integer. But String super Integer is not satisfied, so the compilation fails. See the use of the constraints now? It is to avoid programmers writing things that don't make sense. Another use of the constraints is to allow you to do something like this:
Function<A, B> one = ...
Function<C, SubclassOfB> two = ...
Function<SubclassOfC, B> f = one.compose(two);
There is no relationship between Integer and String in this case, it's all about V.
1) The compose function is part of Interface Function<T,R>. As you can see in documentation for this interface:
Type Parameters:
T - the type of the input to the function
R - the type of the result of the function
2) The super and extends constraints in questions aren't applied to T & R, they're applied to the generic type parameters of a function that you pass in as an argument to the compose function.
Basically this means that if you have:
Function<ClassA, ClassB> one;
Function<SomeSuperClassOfC, SomeSubclassOfA> two;
then it's valid to call
Function<ClassC, ClassB> three = one.compose(two)
I will try to explain from zero;
interface Function<T, R> - this is interface with one method, which must be implemented R apply (T);
in Java prior to 8 we must write:
Function<Integer, String> one = new Function<Integer, String>() {
#Override
public String apply(Integer i) {
return i.toString();
}
};
now you can use it:
String resultApply = one.apply(5);
now, I think, you get the idea.
Here is the snippet (from Java Generics and Collections) and below is question:
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder()
{
return new Comparator<T>() {
public int compare(T o1, T o2) { return o2.compareTo(o1); }
};
}
As I follow you have a method using a wildcard that extends comparable where it compares types T and "above." It then returns a new Comparator which apparrently has a method inside it that returns value of a compareTo using two objects of type T. So questions:
Is this defining a method inside a method? I thought you couldn't do
that in Java.
Is it returning a method? Something I also thought you couldn't do
in Java.
How do I use this? The book uses examples where other, similar,
methods have parameters.
This has no parameters, so where do o1 and o2 come from?
It is an anonymous class:
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
return new Comparator<T>() {
public int compare(T o1, T o2) {
return o2.compareTo(o1);
}
};
}
You are:
Declaring a method compare in the anonymous class, which is in the method reverseOrder.
Returning an instance of the anonymous class.
Declaring o1 and o2 as the parameters of compare.
Questions / Attempted Answers:
As I follow you have a method using a wildcard that extends comparable where it compares types T and "above."
Methods can extend nothing, so no, this is not correct. The method is generic and can be used with concrete class that extends Comparable.
It then returns a new Comparator which apparrently has a method inside it that returns value of a compareTo using two objects of type T. So questions:
OK, kind of correct.
1) Is this defining a method inside a method? I thought you couldn't do that in Java.
It is not a method in a method. It's a method that returns an object of the type Comparator that has its own compare method.
2) Is it returning a method? Something I also thought you couldn't do in Java.
No, it returns an object of an anonymous inner class.
3) How do I use this? The book uses examples where other, similar, methods have parameters. This has no parameters, so where do o1 and o2 come from?
The o1 and o2 are the declared parameters of the Comparator object's compare method.
Following tutorials about Comparators and Anonymous classes might help:
http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
http://www.dummies.com/how-to/content/how-to-use-an-anonymous-class-in-java.html
What I want to do is remove all elements in a collection that are less than a specified object. This is what I have:
static void removeAllLessThan(Collection c, Object x) {
for(Object a : c) if(a.compareTo(x) < 0) c.remove(a);
}
This does not work because Object has no compareTo method. What I want to know is how should I compare between objects? Also what is the natural comparator? Thank you.
using Collection<Comparable> instead of Collection,and implement Comparable to all your items in the collection. And change your method like:
static void removeAllLessThan(Collection<Comparable> c, Comparable x) {
for (Iterator<Comparable> it = c.iterator(); it.hasNext();)
if (it.next().compareTo(x) < 0)
it.remove();
}
Start by using generics, and let the caller declare what type of object he wants to filter by:
static <T> void removeAllLessThan(Collection<T> collection, T t) {...}
This isn't enough, however. You need to use a Comparator<T> to provide the ordering.
static <T> void removeAllLessThan(Collection<T> collection,
Comparator<T> comparator, T t) {...}
Then, allow the user some flexibility when working with inheritance. He has to do the equivalent of t1 < t2, but the comparator can be of any supertype of T, and the collection can be of anything that extends T:
static <T> void removeAllLessThan(Collection<? extends T> collection,
Comparator<? super T> comparator, T t) {...}
Then, there is a mistake with the deletion process. The only mechanism that can delete from a collection while iterating over it is the Iterator. Anything else risks a ConcurrentModificationException.
static <T> void removeAllLessThan(Iterable<? extends T> iterable,
Comparator<? super T> comparator, T t) {
for (Iterator<? extends T> it = iterable.iterator(); it.hasNext();) {
if (comparator.compare(it.next(), t) < 0) {
it.remove();
}
}
}
Note the signature change.
Finally, this is a very specific method. You will need to write lots of nearly identical methods like removeIfGreaterThan, removeIfEqualIgnoringCase, etc. Write a generic removeIf method, with signature
public <T> removeIf(Iterable<? extends T> iterable,
Predicate<? super T> predicate){...}
Predicate is an interface provided by lots of libraries that has just a boolean eval method.
There are two ways to solve this problem.
First, you can use Comparable Interface, which means that the method should be changed into:
static void removeAllLessThan(Collection<Comparable> c, Comparable x) {
for(Comparable a : c) if(a.compareTo(x) < 0) c.remove(a);
}
An object should be comparable to have a method called comparedTo.
Second, you can implement a Comparator to judge which is bigger. If you don't want the object to be comparable, which means you don't want to change the existing code to let it implement Comparable, this is a better way. But the code will be change into:
static void removeAllLessThan(Collection c, Object x, Comparator comp) {
for(Object a : c) if(comp(a, x) < 0) c.remove(a);
}
Here is the javadoc of Comparable and Comparator.