Is it possible to write a single method total
to do a sum of all elements of an ArrayList
, where it is of type <Integer>
or <Long>
?
I cannot just write
public long total(ArrayList<Integer> list)
and
public long total(ArrayList<Long> list)
together as there will be an error of erasure, and Integer
does not automatically extends to Long
and vice versa... but the code inside is identical!
Yes, you can implement such a method, since both Integer
and Long
extend Number
. For example you can use a wildcard type for the list element type:
public static long total(List<? extends Number> list) {
long sum = 0;
for (Number n : list) {
if (!(n instanceof Byte || n instanceof Short || n instanceof Integer || n instanceof Long)) {
throw new IllegalArgumentException();
}
sum += n.longValue();
}
return sum;
}
This only works for the integral types however, since the sum
variable and the return value are of type long
.
Ideally you would like to be able to also use the method with Float
s and Double
s and return an object of the same type as the list element type, but this is not easy to do for two reasons:
Number
is to get its value as one of the primitive number types. You can not sum two of them in a number dependent way.EDIT: Much later...
Just for fun, lets do this in a nice way for Java. The thing you have to do is to manually provide the two operations mentioned above. A kind of value with two such operation is usually called a monoid in the context of algebra and functional programming.
The problem can be solved by creating objects that represent the monoid operations:
interface MonoidOps<T> {
T id();
T op(T o1, T o2);
}
The total
method can now be implemented to take an object of this type in addition to the list:
public static <T> T total(List<T> list, MonoidOps<T> ops) {
T sum = ops.id();
for (T e : list) {
sum = ops.op(e, sum);
}
return sum;
}
To provide MonoidOps
implementations for the numeric classes, lets create a simple helper class:
class SimpleMonoidOps<T> implements MonoidOps<T> {
private final T idElem;
private final BinaryOperator<T> operation;
public SimpleMonoidOps(T idElem, BinaryOperator<T> operation) {
this.idElem = idElem;
this.operation = operation;
}
public T id() {
return idElem;
}
public T op(T o1, T o2) {
return operation.apply(o1, o2);
}
}
The MonoidOps
implementations can now be written neatly like this:
static final MonoidOps<Integer> INT_MONOID_OPS = new SimpleMonoidOps<>(0, Integer::sum);
static final MonoidOps<Double> DOUBLE_MONOID_OPS = new SimpleMonoidOps<>(0.0, Double::sum);
And the total
method would be called like this:
int sum = total(Arrays.asList(1, 2, 3), INT_MONOID_OPS);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With