Search code examples
javafunctional-interfacebinary-operators

Method declaration with a function to extract fields of an object and a binary operator which will be applied to those fields


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?


Solution

  • 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.