Given the following sample class Foo
@Getter
@AllArgsConstructor
@ToString
static class Foo {
int field1;
int field2;
String field3;
}
I want to declare a method, let's call it applyBinOperator
, which accepts two Foo
objects a key-extractor and a binary operator and apply that operator to the extracted fields of the Foo objects and returns the result. So basically I want to call the method in the following way or something similar:
Foo foo1 = new Foo(10, 20, "first");
Foo foo2 = new Foo(100, 200, "second");
int sum = applyBinOperator(foo1, foo2, Foo::getField1, (a,b) -> a b);
int prod = applyBinOperator(foo1, foo2, Foo::getField2, (a,b) -> a*b);
String concat = applyBinOperator(foo1, foo2, Foo::getField3, (a,b) -> String.join(a,b));
//and get sum = 110, prod = 4000 and concat = firstsecond
But I am struggling to find the correct syntax to define the method since I am not very familiar with generics. I have tried the following but it doesn't compile yet:
public static <T> T applyBinOperator(Foo foo1, Foo foo2,
Function<? super T, ?> keyExtractor, BinaryOperator<T> binaryOperator) {
return binaryOperator.apply(keyExtractor.apply(foo1), keyExtractor.apply(foo2));
}
Can someone help me with the correct syntax?
CodePudding user response:
You seem to have just mixed up the order of the type parameters of Function
. To write "a function that takes a Foo
and returns a T
", it is Function<Foo, T>
:
public static <T> T applyBinOperator(Foo foo1, Foo foo2,
Function<Foo, T> keyExtractor, BinaryOperator<T> binaryOperator) {
return binaryOperator.apply(keyExtractor.apply(foo1), keyExtractor.apply(foo2));
}
We can make the Foo
part generic too, and also apply PECS:
public static <T, U> T applyBinOperator(U foo1, U foo2,
Function<? super U, ? extends T> keyExtractor, BinaryOperator<T> binaryOperator) {
return binaryOperator.apply(keyExtractor.apply(foo1), keyExtractor.apply(foo2));
}
Also, String.join
does not join "first"
and "second"
together. You probably meant String.concat
, or just use
, which works with strings too.