views:

142

answers:

2

Hi,

I want to make a generic method which makes the total sum of a List of numbers.

What I was trying is this:

public static <T extends Number> T sumList(List<T> data)
{
    T total = 0;
    for (T elem : data)
    {
        total += elem;
    }
    return total;
}

But the problem is that there is no += operator in T and that total can't be assigned to zero.

How can I do this?

Thanks

+2  A: 

I've done that recently (based on lambdaj code) beware it will need all your elements to be the same type (you can't really add a Byte and a BigDecimal) and can throw a CCE if it isn't the case and won't handle custom Number :

public class SumAggregator<T extends Number> {
    public T aggregate(Iterable<T> iterable) {
        T result = null;
        for (T item : iterable) {
            result = aggregate(result, item);
        }
        return result;
    }


    @SuppressWarnings("unchecked")
    protected T aggregate(T first, T second) {
        if (first == null) {
            return second;
        } else if (second == null) {
            return first;
        } else if (first instanceof BigDecimal) {
            return (T) aggregate((BigDecimal) first, (BigDecimal) second);
        } else if (second instanceof BigInteger) {
            return (T) aggregate((BigInteger) first, (BigInteger) second);
        } else if (first instanceof Byte) {
            return (T) aggregate((Byte) first, (Byte) second);
        } else if (first instanceof Double) {
            return (T) aggregate((Double) first, (Double) second);
        } else if (first instanceof Float) {
            return (T) aggregate((Float) first, (Float) second);
        } else if (first instanceof Integer) {
            return (T) aggregate((Integer) first, (Integer) second);
        } else if (first instanceof Long) {
            return (T) aggregate((Long) first, (Long) second);
        } else if (first instanceof Short) {
            return (T) aggregate((Short) first, (Short) second);
        } else {
            throw new UnsupportedOperationException("SumAggregator only supports official subclasses of Number");
        }
    }

    private BigDecimal aggregate(BigDecimal first, BigDecimal second) {
        return first.add(second);
    }

    private BigInteger aggregate(BigInteger first, BigInteger second) {
        return first.add(second);
    }

    private Byte aggregate(Byte first, Byte second) {
        return (byte) (first + second);
    }

    private Double aggregate(Double first, Double second) {
        return first + second;
    }

    private Float aggregate(Float first, Float second) {
        return first + second;
    }

    private Integer aggregate(Integer first, Integer second) {
        return first + second;
    }

    private Long aggregate(Long first, Long second) {
        return first + second;
    }

    private Short aggregate(Short first, Short second) {
        return (short) (first + second);
    }
}

This code executed on ideone with examples.

Colin Hebert
Thanks, Colin. But in my situation, I want to use short code. I will remember your post when I really need the generics. But I can do without.
Martijn Courteaux
@Martijn Courteaux, in my case, I couldn't do without generics, but if you can avoid generics and avoid to end up with this kind of code (which is IMO really heavy [tons of cast]) you should do without generics.
Colin Hebert
@Colin: Indeed, that's the point.
Martijn Courteaux
@Colin: Apparently I'm the downvote here and I don't remember doing it; it must've been a mistake. If you choose to edit it I could remove my downvote; otherwise sorry, SO won't let me remove it!
Mark Peters
+5  A: 

There are ways you can hack this together but in all honestly, generics is simply not the way to go here. Build a method for each concrete primitive wrapper type and implement them separately. It'll be way too much of a headache to make it generic; arithmetic operations can't happen generically.

You don't really gain anything by making it generic, either. It's such simple and constant code that you aren't worried about code duplication, since it's not going to change. And people aren't going to be passing in their own type of Number to your code; the domain of types it applies to is already well defined and finite.

Mark Peters
It hurts that this is true, but it is (+1)
seanizer