2010-10-03 29 views
16

Quiero hacer un método genérico que hace la suma total de un List de números.Java: métodos genéricos y números

Lo que estaba tratando es la siguiente:

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

Pero el problema es que there is no += operator in T y que total can't be assigned to zero.

¿Cómo puedo hacer esto?

Gracias

+5

Esto explica claramente por qué C++ es más superior a Java. :-P –

+1

@Chris: De hecho. C++ es mejor en este caso ... –

+0

@ Cris, Martijn: ¿Puedes apuntar a un código de muestra que hace la tarea anterior? He perdido el contacto con C++. Solo quiero ver cómo se hará en C++. – Emil

Respuesta

18

Hay maneras en que puede hackear esto juntos, pero honestamente, los genéricos simplemente no son el camino a seguir aquí. Cree un método para cada tipo de envoltura primitiva de concreto e impleméntelos por separado. Será demasiado dolor de cabeza hacerlo genérico; las operaciones aritméticas no pueden suceder genéricamente.

No gana nada haciéndolo genérico tampoco. Es un código tan simple y constante que no está preocupado por la duplicación de código, ya que no va a cambiar. Y las personas no van a pasar su propio tipo de Número a su código; el dominio de tipos al que se aplica ya está bien definido y es finito.

+5

Me duele que esto sea cierto, pero es (+1) –

+10

wow, esto me pone triste. – nont

4

lo he hecho recientemente (basado en lambdaj código) ten en cuenta que se necesita todos sus elementos a ser del mismo tipo (realmente no se puede añadir un Byte y una BigDecimal) y puede lanzar una CCE si no es el caso y no se encargará de encargo 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.

+0

Gracias, Colin. Pero en mi situación, quiero usar código corto. Recordaré tu publicación cuando realmente necesite los genéricos. Pero puedo prescindir. –

+0

@Martijn Courteaux, en mi caso, no podría prescindir de los genéricos, pero si puedes evitar los genéricos y evitar terminar con este tipo de código (que es IMO realmente pesado [toneladas de yeso]) deberías prescindir de los genéricos . –

+0

De hecho, ese es el punto. –

0

Puede usar una biblioteca, como Generic Java Math (su parte de números), que proporciona operaciones genéricas para las subclases de Número. Proporciona una forma de trabajar genéricamente con números, tal como en su ejemplo, pero con pasar objetos Aritméticos alrededor, que hace el cálculo real. Ver ejemplo en la página de inicio.
Debe usar tipos encuadrados, de modo que si necesita velocidad, ninguna implementación genérica puede hacer eso en Java, debe usar tipos primitivos.

0

Tener un vistazo a ejemplo de método genérico siguiente para la suma de cualquier tipo Número de listas de variables ... estoy seguro de que esto es lo que estaba pidiendo ..

Mark Peters es también justo en su respuesta, pero esta también es una solución a seguir.

public class GenericSum { 
@SuppressWarnings("unchecked") 
public static <E> E sumArray(E[] inputArray) { 
    Double result = 0.0; 
    // Sum array elements 
    for (E element : inputArray) { 
     result = ((Number) result).doubleValue() 
       + ((Number) element).doubleValue(); 
    } 
    return ((E) result); 
} 

public static void main(String args[]) { 
    // Create arrays of Integer, Double 
    Integer[] intArray = { 1, 2, 3, 4, 5 }; 
    Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; 

    System.out.println("Sum of doubles : " + sumArray(intArray)); 
    System.out.println("Sum of doubles : " + sumArray(doubleArray)); 
} 

} 
+0

esto convierte todo en doble, lo cual no es el punto – NimChimpsky