不同类型的ArrayList的总和

时间:2015-06-10 17:45:45

标签: java arraylist

是否可以编写单个方法total来对ArrayList的所有元素求和,其类型为<Integer><Long>

我不能只写

public long total(ArrayList<Integer> list) 

public long total(ArrayList<Long> list) 

因为擦除错误,Integer不会自动扩展到Long,反之亦然......但内部代码完全相同!

3 个答案:

答案 0 :(得分:11)

是的,您可以实施此类方法,因为IntegerLong都会延伸Number。例如,您可以使用wildcard 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;
}

这仅适用于整数类型,因为sum变量和返回值的类型为long

理想情况下,您希望能够将此方法与FloatDouble一起使用,并返回与列表元素类型相同类型的对象,但这并不容易有两个原因:

  1. 使用Number唯一能做的就是将其值作为原始数字类型之一。你不能以数量依赖的方式对它们中的两个进行求和。
  2. 无法创建正确类的0对象。
  3. 编辑: 很久以后......

    只是为了好玩,让我们以一种很好的方式为Java做这件事。您需要做的是手动提供上面提到的两个操作。在代数和函数式编程的上下文中,一种具有两个这样的操作的值通常称为monoid

    可以通过创建表示幺半群操作的对象来解决问题:

    interface MonoidOps<T> {
        T id();
        T op(T o1, T o2);
    }
    

    现在可以实现total方法,除了列表之外还可以使用此类型的对象:

    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;
    }
    

    为数字类提供MonoidOps实现,让我们创建一个简单的帮助类:

    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);
        }
    }
    

    MonoidOps实现现在可以像这样整洁地编写:

    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);
    

    total方法会像这样调用:

    int sum = total(Arrays.asList(1, 2, 3), INT_MONOID_OPS);
    

答案 1 :(得分:1)

您还可以在Java 8中使用流

public static <T extends Number> long sumList(List<T> list)
{
    return list.stream().mapToLong(a -> a.longValue()).sum();
}

答案 2 :(得分:0)

您可以将Java的泛型用于此

public <T extends Number> T total(List<T> list) {
    T sum = 0;
    for (T n : list) {
        sum += n.longValue();
    }
    return sum;
}

知道T永远是Number,事情就会简化。但是,如果需要,此解决方案也可以用于String。唯一的变化是extends部分。

相关问题