Johnyb
Johnyb

Reputation: 1316

return method refference to stream

I have a class Care

class Car{
  private int wheels;
  private int doors;
 
  ...   

  public int getWheels(){ return wheels;}
  public int getDoors(){ return doors:}
}

And I have a collection of the cars

List<Car> cars = ...

I want to calculate the average numbers of doors and windows in the collection. I could do this:

cars.stream().mapToInt(Car::getWheels).avg().orElse(0.0)
cars.stream().mapToInt(Car::getDoors).avg().orElse(0.0)

However, I want to create a dynamic function for this, for example:

public double calculateAvgOfProperty(List<Car> cars, String property){
  Function<Car,Integer> mapper = decideMapper(property);
  return cars.stream().maptoInt(mapper).avg().orElse(0.0);
}

public Function<Car,Integer> decideMapper(String ppr){
   if( ppr.equals("doors")  return Car::getDoors;
   if( ppr.equals("wheels") return Car::getWheels;
}

However, .mapToInt() requires ToIntFunction<? super T> mapper as argument, but the method reference is Function<Car,Integer>, and casting does not work.

However when I directly pass the method reference, for example .mapToInt(Car::getDoors), it works.

How to cast correctly cast Function<Car,Integer> to required type then?

Upvotes: 0

Views: 99

Answers (3)

Giorgi Tsiklauri
Giorgi Tsiklauri

Reputation: 11130

I'm not sure what you're trying to achieve, but I'm sure, that you have quite a few compile time errors in your code:

  1. Missing some closing braces in the decideMapper method;
  2. You don't really return anything for the default case, from decideMapper;
  3. calling some .avg() on IntStream, which is not available.

Upvotes: 1

M A
M A

Reputation: 72874

You should not cast a Function to a ToIntFunction as they are not associated (ToIntFunction does not extend Function). They are however both functional interfaces, so the method reference can also be inferred directly as a ToIntFunction.

There is an average() method defined in IntStream:

public double calculateAvgOfProperty(List<Car> cars, String property) {
    ToIntFunction<Car> mapper = decideMapper(property);
    return cars.stream().mapToInt(mapper).average().orElse(0.0);
}

public ToIntFunction<Car> decideMapper(String ppr){
     if( ppr.equals("doors"))  return Car::getDoors;
     if( ppr.equals("wheels")) return Car::getWheels;
     ...
}

Upvotes: 3

Youcef LAIDANI
Youcef LAIDANI

Reputation: 60036

Do you mean to create a method like this:

private double calculateAvgOfProperty(List<Car> cars, Function<Car, Integer> function) {
    return cars.stream().mapToDouble(function::apply)
            .average()
            .orElse(0.0);
}

and then you can only call:

double r1 = calculateAvgOfProperty(cars, Car::getWheels);
double r2 = calculateAvgOfProperty(cars, Car::getDoors);

I don't understand very well your question, but you can replace mapToDouble with mapToInt if you want.

Upvotes: 2

Related Questions