Providing a field accessor method as an argument

G'day comrades. I have a problem.

I have two methods which are completely duplicate apart from that they are accessing a different field. I cannot pass the field value as a parameter because accessing takes place inside a loop (simplified example):

   public final class Thing {

        ImmutableList<Box> boxes;

        public int getNumberOfApples() {
            int total = 0;
            for (Box box : boxes) {
                total += box.getApplesCount();
            }
            return total;
        }

        public int getNumberOfPears() {
            int total = 0;
            for (Box box : boxes) {
                total += box.getPearsCount();
            }
            return total;
        }
    }

I could put my fruit into a map and passed the field name as a parameter but it looks dirty and I am quite happy with the current class composition. So the question is - how do I refactor my code to have a single method of type:

public int getNumberOfFruit(SomethingMagic) {
    moreMagic;
    return total;
}

Cheerio.

Jon Skeet
people
quotationmark

Well, you could have something like:

public interface Function<In, Out> {
    Out apply(In input);
}

Then:

public int getCount(Function<Box, Integer> projection) {
    int total = 0;
    for (Box box : boxes) {
        total += projection(box);
    }
    return total;
}

For the moment constructing that projection will be ugly, e.g.

int pears = thing.getCount(new Function<Box, Integer>() {
    @Override public Integer apply(Box input) {
        return box.getPearsCount();
    }
});

but in Java 8, it'll be much simpler with lambda expressions:

int pears = thing.getCount(box -> box.getPearsCount());

Note that Raffaele Rossi's answer is slightly more specific than mine by making the interface non-generic. This means it can be more efficient, as there's no need to box the counts - but less reusable, of course. Which approach you decide to use is a judgement call which will largely depend on your actual use case.

people

See more on this question at Stackoverflow