'How to put class field into method argument to avoid code repeat
I am currently solving this issue. For example. I have two classes. One for item and second for some kind of records of these items. What I need to do, if I want to have a few methods for get average of different kind from all items in collection. In my example, there is average of price, mass and volume. The methods are repetitive and the only one different thing is the getter. So, is there any option, how to have one private method for counting and another three public, that will use this one private method and somehow put the field as argument?
Item class
public class Item {
private double price;
private double mass;
private double volume;
public double getPrice() {
return price;
}
public double getMass() {
return mass;
}
public double getVolume() {
return volume;
}
}
Stock class
package model;
import java.util.ArrayList;
import java.util.List;
public class Stock {
private List<Item> items;
public Stock() {
items = new ArrayList<>();
}
public double getAveragePrice() {
double sum = 0;
if (!items.isEmpty()) {
for (Item item : items) {
sum += item.getPrice();
}
return sum / items.size();
}
return sum;
}
public double getAverageMass() {
double sum = 0;
if (!items.isEmpty()) {
for (Item item : items) {
sum += item.getMass();
}
return sum / items.size();
}
return sum;
}
public double getAverageVolume() {
double sum = 0;
if (!items.isEmpty()) {
for (Item item : items) {
sum += item.getVolume();
}
return sum / items.size();
}
return sum;
}
}
Solution 1:[1]
As Johannes Kuhn proposed in a comment, you can pass the getter as a ToDoubleFunction<Item>
to your calculation method:
private double calcAverage(ToDoubleFunction<Item> getter) {
double sum = 0;
if (!items.isEmpty()) {
for (Item item : items) {
sum += getter.applyAsDouble(item);
}
return sum / items.size();
}
return sum;
}
public double getAveragePrice() {
return calcAverage(Item::getPrice);
}
You can then reuse the calculation:
public double getAverageMass() {
return calcAverage(Item::getMass);
}
public double getAverageVolume() {
return calcAverage(Item::getVolume);
}
Solution 2:[2]
Here is a solution using stream API
public double getAverageMass() {
return calcAverage(Item::getMass);
}
public double getAverageVolume() {
return calcAverage(Item::getVolume);
}
private double calcAverage(ToDoubleFunction<Item> getter) {
return items.stream().mapToDouble(getter).average().orElse(0);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Hulk |
Solution 2 | Daniel HanĂ¡k |