Home > database >  Passing function as argument to a Function, and using it on Generic object
Passing function as argument to a Function, and using it on Generic object

Time:10-21

I would like to do something like below.

private <T> void sliceGenericData (List<T> peData, **FunctionType** getterFunctionX) {
    // ... Some Code ...


    <T>.getterFunction()


    // ... Some Code ...

}

A and B class will be my generic type as <T>. Example for a getter function for class A and B.

public class A{
  long x = 5;
  public long getterFunction1(){
     return x;
  }
}

public class B{
  long x = 1;
  public long getterFunction2(){
     return x;
  }
}

I want to pass a getterFunction as argument to my sliceGenericData() and I would like to use it on type <T> (Class A or B). Since those classes have different name of getter functions as getterFunction2, getterFunction1. How can I do it?

CodePudding user response:

You can pass a function taking the type as param and producing a Long like this:

private <T> void sliceGenericData (List<T> peData, Function<T, Long> fn) 
{ 
  ... 
  // apply your Object
  Long res = fn.apply(myObj);
  ...
}

Invoke the method by providing the appropriate method for the type:

sliceGenericData(myList, A::getterFunction1);

CodePudding user response:

If I understood your intention, you want to turn a List<T> into a List<Long>. I so your function should not be parameterless, instead it should consume an argument of type T to produce a long value.

But to make a function be capable to dial with these classes they need to conform to the same contract, and we already have such contract in the JDK - LongSupplier.

And there's one more thing - if you make your classes implement LongSupplier interface, the function would not be needed.

Note that implementing the contract of LongSupplier would not affect your existing code anyhow. Method getAsLong() can delegate to methods like getterFunction1().

public class A implements LongSupplier {
    
    public long getterFunction1() {
        // proper logic here
    }
    
    public long getAsLong() {
        return getterFunction1();
    }
}

public class B implements LongSupplier {

    public long getterFunction2() {
        // proper logic here
    }
    
    public long getAsLong() {
        return getterFunction2();
    }
}

Note:

  • If A and B differ only by the value of an attribute - you don't need two classes.
  • Only if you have a more complicated logic of generating the resulting value (instead of simply retrieving what is stored in a field), it would be justifiable to have separate classes implementing that logic.

And your method might look like this:

private void sliceGenericData(List<LongSupplier> peData) {
    // ... Some Code ...

    List<Long> longs = peData.stream()
        .map(LongSupplier::getAsLong)
        .toList(); // or collect(Collectors.toList())
    
    // ... Some Code ...
    
}
  • Related