I write a method to calculate QoQ generally.
My idea is to iterate all the fields and calculate if it's long , integer, float or double and set the field name and the result to a map.
It was easy to write this code, but I found it's too ugly :
public static <T> Map<String, String> calculateQoq(final T now, final T before) {
final Field[] declaredFields = now.getClass().getDeclaredFields();
if (ArrayUtils.isEmpty(declaredFields)) {
return Collections.emptyMap();
}
final Map<String, String> map = new HashMap<>(declaredFields.length, 1);
for (final Field f : now.getClass().getDeclaredFields()) {
try {
f.setAccessible(true);
final Object a = f.get(before);
if (a instanceof Integer) {
final Integer beforeNum = (Integer)a;
if (beforeNum == null || beforeNum == 0) {
map.put(f.getName(), ZERO);
continue;
}
final Integer nowNum = (Integer) f.get(now);
if (nowNum == null) {
map.put(f.getName(), ZERO);
continue;
}
map.put(f.getName(), formatTwoFraction((nowNum - beforeNum) * 1.0 / beforeNum));
} else if (a instanceof Long) {
final Long beforeNum = (Long)a;
if (beforeNum == null || beforeNum == 0) {
map.put(f.getName(), ZERO);
continue;
}
final Long nowNum = (Long) f.get(now);
if (nowNum == null) {
map.put(f.getName(), ZERO);
continue;
}
map.put(f.getName(), formatTwoFraction((nowNum - beforeNum) * 1.0 / beforeNum));
} else if (a instanceof Double) {
final Double beforeNum = (Double)a;
if (beforeNum == null || beforeNum == 0) {
map.put(f.getName(), ZERO);
continue;
}
final Double nowNum = (Double) f.get(now);
if (nowNum == null) {
map.put(f.getName(), ZERO);
continue;
}
map.put(f.getName(), formatTwoFraction((nowNum - beforeNum) / beforeNum));
} else if (a instanceof Float) {
final Float beforeNum = (Float)a;
if (beforeNum == null || beforeNum == 0) {
map.put(f.getName(), ZERO);
continue;
}
final Float nowNum = (Float) f.get(now);
if (nowNum == null) {
map.put(f.getName(), ZERO);
continue;
}
map.put(f.getName(), formatTwoFraction((nowNum - beforeNum) / beforeNum));
}
} catch (final Exception e) {
LOG.error("calculateQoq - get field failed - " + f.getName(), e);
}
}
return map;
}
I just repeat the nearly same logic four times, I try to use something like <T extends Number> void doXXX(T before, T now)
But Number
can't be calculated.
And Integer, Long and others don't have some common interface like NumberEquals
(the default implementation of equals
do type checking) or Divideable
...
There is no macros in java too...
I tried some times emmmm but no solution yet.
So I wonder is there any way to do abstraction and reduce this logic.
Aucun commentaire:
Enregistrer un commentaire