Arian
Arian

Reputation: 7719

How to pass in method as a parameter

I have a bunch of methods that are basically doing the same thing: selecting top N instances of a class based on value returned by its different methods all returning double value.

So for example, for objects of a class implementing the following interface:

interface A {
    Double getSalary();
    Double getAge();
    Double getHeight();
}

I want to select N objects with the highest of values returned by each method.

Right now I have 3 methods:

List<A> getTopItemsBySalary(List<A> elements);
List<A> getTopItemsByAge(List<A> elements);
List<A> getTopItemsByHeight(List<A> elements);

That has this body:

List<A> getTopItemsBySalary(List<A> elements, int n) {
    return elements.stream()
              .filter(a -> a.getSalary() != null)                 
              .sorted(Comparator.comparingDouble(A::getSalary).reversed())
              .limit(n)
              .collect(Collectors.toList());
}

How can I pass in the method and just have one method?

Upvotes: 3

Views: 126

Answers (3)

theincrediblethor
theincrediblethor

Reputation: 448

You can pass in the field name to a generic getTopItems function and use java.beans.PropertyDescriptor

List<A> getTopItemsByField(List<A> elements, String field) {
PropertyDescriptor pd = new PropertyDescriptor(field, A.class);
Method getter = pd.getReadMethod();
return elements.stream()
          .filter(a -> getter(a) != null)                 
          .sorted(Comparator.comparingDouble(a->a.getter(a)).reversed())
          .limit(n)
          .collect(Collectors.toList());
}

Upvotes: 0

ernest_k
ernest_k

Reputation: 45309

You can use a Function that converts A to Double, like:

List<A> getTopItems(List<A> elements, Function<A, Double> mapper, int n) {
    return elements.stream()
              .filter(a -> null != mapper.apply(a))                 
              .sorted(Comparator.<A>comparingDouble(a -> mapper.apply(a))
                      .reversed())
              .limit(n)
              .collect(Collectors.toList());
}

And you can call it using:

List<A> top10BySalary = getTopItems(list, A::getSalary, 10);
List<A> top10ByAge = getTopItems(list, A::getAge, 10);

If your getters are expected to always return a non-null, then ToDoubleFunction is a better type to use (but it won't work if your Double return values may be null):

List<A> getTopItems(List<A> elements, ToDoubleFunction<A> mapper, int n) {
    return elements.stream()
              .sorted(Comparator.comparingDouble(mapper).reversed())
              .limit(n)
              .collect(Collectors.toList());
}

Upvotes: 6

AmeyaN99
AmeyaN99

Reputation: 172

i think you could change the function name and add if conditions:

List<A> getTopItems(List<A> elements, int n, String byWhat) {
if (byWhat.equals("Salary"))
    return elements.stream()
              .filter(a -> a.getSalary() != null)                 
              .sorted(Comparator.comparingDouble(A::getSalary).reversed())
              .limit(n)
              .collect(Collectors.toList());
if (byWhat.equals("Height"))
    return elements.stream()
              .filter(a -> a.getHeight() != null)                 
              .sorted(Comparator.comparingDouble(A::getHeight).reversed())
              .limit(n)
              .collect(Collectors.toList());
if (byWhat.equals("Age"))
    return elements.stream()
              .filter(a -> a.getAge() != null)                 
              .sorted(Comparator.comparingDouble(A::getAge).reversed())
              .limit(n)
              .collect(Collectors.toList());

}

Upvotes: 0

Related Questions