Nick Kyrpenko
Nick Kyrpenko

Reputation: 69

Create Comparator using map of getter method references

I have tried to create a Comparator based on object fields that have non-null values using Comparator.compare and then chain it with Comparator.thenCompare. I have a HashMap that stores a field as a key and getter method reference as a value.

Here is my enum of fields :

 public enum BikeProperty {
     BRAND,
     MAX_SPEED,
     WEIGHT,
     SIZE_OF_WHEEL,
     NUMBER_OF_GEARS,
     IS_LIGHT_AVAILABLE,
     BATTERY_CAPACITY,
     COLOR,
     PRICE
}

Each of this fields related to some field in Bike object.

Next stop is my HashMap that looks like this:

    Map<BikeProperty, Function<Bike, Comparable<?>>> fieldToFieldExtractor = new HashMap<>();
    fieldToFieldExtractor.put(BikeProperty.MAX_SPEED, Bike::getMaxSpeed);
    fieldToFieldExtractor.put(BikeProperty.WEIGHT, Bike::getWeight);
    fieldToFieldExtractor.put(BikeProperty.SIZE_OF_WHEEL, Bike::getSizeOfWheels);
    fieldToFieldExtractor.put(BikeProperty.NUMBER_OF_GEARS, Bike::getNumberOfGears);
    fieldToFieldExtractor.put(BikeProperty.IS_LIGHT_AVAILABLE, Bike::isLightsAvailable);
    fieldToFieldExtractor.put(BikeProperty.BATTERY_CAPACITY, Bike::getBatteryCapacity);
    fieldToFieldExtractor.put(BikeProperty.COLOR, Bike::getColor);
    fieldToFieldExtractor.put(BikeProperty.PRICE, Bike::getPrice);

And finally my method:

public Comparator<Bike> provideComparatorByFields(Set<BikeProperty> fields) {
    Comparator<Bike> comparator = Comparator.comparing(Bike::getBrand);
    fields
            .forEach(s -> comparator.thenComparing(fieldToFieldExtractor.get(s)));
    return comparator;
}

My idea is to pass to method already filtered Set<BikePropery>, iterate through this and chain comparator methods.

For example, for given set Set.of(BikeProperty.PRICE,BikeProperty.IS_LIGHT_AVAILABLE), generate following comparator : Comparator.compare(Bike::getBrand).thenCompare(Bike::getPrice).thenCompare(Bike::isLightAvailable)

Problem : Created comparator have only one default comparing of Bike::getBrand(). Therefore, I had a question, is it possible to do so at all, and if possible, bring some advice. Thank you!

Update

When I`m creating comparator (for example) from my main method, it looks like this : enter image description here

enter image description here

But when I`m creating it in my method by forEach loop it looks like this:

So it does not append any thenComparing() keyExtractor to comparator

Upvotes: 1

Views: 422

Answers (1)

Benjamin Maurer
Benjamin Maurer

Reputation: 3753

You are not storing the changes. thenCompare doesn't modify the original comparator, but returns a new one.

for (var s : fields) {
    comparator = comparator.thenComparing(fieldToFieldExtractor.get(s)));
}

Upvotes: 1

Related Questions