2014-01-06 1 views
3

Мне нужно создать вспомогательный метод, который позволяет создать сумму любого Итерабельного <? расширяет номер >, потому что мы имеем много векторов и требуют быстрого метода, чтобы определить сумму, поэтому я создал следующий метод:Java 1.7: Сумма Iterable <T extends Number>

static Integer sum(Iterable<Integer> it) { 
    Integer result = 0; 
    for(T next : it) { 
     result += next; 
    } 
    return result; 
} 

Этот метод работает только для целых чисел, однако, но у нас есть двойники и тоскует. Потому что у вас не может быть двух методов с одной и той же сигнатурой (наш компилятор считает, что целочисленная сумма (Iterable <Integer>) имеет ту же подпись, что и Double sum (Iterable <Double>).) Я попытался написать один метод с generics.

private static <T extends Number> T sum(Iterable<? extends T> it) { 
    T result; 
    for(T next : it) { 
     result += next; 
    } 
    return result; 
} 

Однако этот метод не будет скомпилирован (причина: оператор + = не определен для объекта, объекта). Что я могу сделать здесь? Я знаю, что на C++ вы можете перегружать операторы, но не на Java. Но каждый класс, который расширяет Number, перегружает оператор + =. Что я могу сделать здесь?

Заранее спасибо.

+0

Вы можете использовать InstanceOf Double, Integer и т.д., и бросил его в таком случае присвоить числовой тип – rkosegi

+0

InstanceOf не работает, потому что _result_ является недействительным после его объявления ... –

+1

, если это будет один из самые важные вычисления в программе, я предлагаю в первую очередь избавиться от AnyGenericClass , а также AnyGenericClass , потому что он ОЧЕНЬ неэффективен и вместо этого использует массивы примитивных типов. –

ответ

0

Посмотрите How to add two java.lang.Numbers?

Вы не знаете тип номеров вы подытожить так либо использовать next.doubleValue(), если вы можете терпеть потери точности или посмотреть на BigDecimal, если вы хотите сохраняйте точность (используйте конструктор String).

0

Причина, по которой ваш метод работает с java.lang.Integer, вызван auto-boxing.

К сожалению, java.lang.Number представляет собой представление числового значения в очень общем смысле, в частности, что вы получаете его как один из конкретных типов номеров, но не можете делать с ним ничего другого.

В этом случае это означает, что у вас будет метод sum для каждого возвращаемого типа, который вам очень важен.

В основном вы будете в конечном итоге с чем-то вроде этого (который предполагает, вы хотите, чтобы округлить число с плавающей запятой, подводя их к не-формат с плавающей запятой):

public class SumUtils 
{ 
    public static Integer sumToInteger(Iterable<Number> numbers) 
    { 
    long sum = 0; 

    for (Number number : numbers) 
    { 
     sum += Math.round(number.doubleValue()); 
    } 

    if (sum > Integer.MAX_INT) 
    { 
     throw new IllegalStateException(); 
    } 

    return (int)sum; 
    } 

    public static Long sumToLong(Iterable<Number> numbers) 
    { 
    long sum = 0; 

    for (Number number : numbers) 
    { 
     sum += Math.round(number.doubleValue()); 
    } 

    return sum; 
    } 

    public static Float sumToFloat(Iterable<Number> numbers) 
    { 
    double sum = 0; 

    for (Number number : numbers) 
    { 
     sum += number.doubleValue(); 
    } 

    if (sum > Float.MAX_FLOAT) 
    { 
     throw new IllegalStateException(); 
    } 

    return (float)sum; 
    } 

    public static Double sumToDouble(Iterable<Number> numbers) 
    { 
    double sum = 0; 

    for (Number number : numbers) 
    { 
     sum += number.doubleValue(); 
    } 

    return sum; 
    } 

    public static BigDecimal sumToBigDecimal(Iterable<Number> numbers) 
    { 
    BigDecimal sum = BigDecimal.ZERO; 

    for (Number number : numbers) 
    { 
     if (number instanceof BigDecimal) 
     { 
     sum = sum.add((BigDecimal)number); 
     } 
     else 
     { 
     sum = sum.add(new BigDecimal(number.doubleValue())); 
     } 
    } 

    return sum; 
    } 
} 
+0

Наша проблема заключается в том, что мы не знаем, какой тип имеет Iterable, который мы получаем через интерфейс. Мы знаем только, что это любой тип Iterable . Ваше решение кажется хорошим решением, но на самом деле не соответствует нашим требованиям. –

+0

ОК - в этом случае вам просто нужно рассматривать его как двойное и круглое соответственно. Я изменю ответ, чтобы показать вам. –

0

Если все числа того же (неизвестного) типа, то вам не нужно проверять каждый элемент, просто введите тип первого и выберите соответствующий цикл для вычисления суммы в double, long, BigDecimal или BigInteger.

0

Вы можете попробовать InstanceOf проверки, а затем кастинг на каждой итерации Ламе решения, Howewer

 private static <T extends Number> T sum(Iterable<? extends T> it) 
     { 
      T result = null; 
      Integer inttt = null; 

      if (it.iterator() 
       .hasNext() && it.iterator() 
       .next() instanceof Integer) 
      { 

      for (T next : it) 
      { 
       if (next instanceof Integer) 
       { 
        inttt += (Integer) next; 
       } 

      } 
       return (T)inttt; 
      } 
// For other types here 
      return result; 
     } 
+0

Этот метод будет разбит, если он называется 'sum (Arrays.asList (1, 1.2, 3)'. –

2

Если число не может быть BigInteger s или BigDecimal s, вы можете попробовать преобразовать их в double с и суммировать их такие как:

double result = 0; 
for (T number : it) { 
    result += number.doubleValue(); 
} 
+0

Это приведет к неправильным ответам во многих ситуациях. –

+0

Можете ли вы подробно остановиться на этом? – Natix

+0

Просто посмотрите на этот ответ (я слишком ленив, чтобы повторить все снова) http://stackoverflow.com/a/4970056/1418097 –

0

Итак, я написал следующее сейчас, но я не очень доволен ...

static <T extends Number> T sum(Iterable<? extends T> it) { 
    Iterator<? extends T> iterator = it.iterator(); 
    Number first = iterator.next(); 

    if(first instanceof Integer) { 
     Integer _result = (Integer) first; 
     for(T next : it) 
      _result+=(Integer)next; 
     return (T) _result; 
    } 
    else if(first instanceof Double) { 
     Double _result = (Double) first; 
     for(T next : it) 
      _result+=(Double)next; 
     return (T) _result; 
    } 
    else if(first instanceof Long) { 
     Long _result = (Long) first; 
     for(T next : it) 
      _result+=(Long)next; 
     return (T) _result; 
    } 
    else if(first instanceof Float) { 
     Float _result = (Float) first; 
     for(T next : it) 
      _result+=(Float)next; 
     return (T) _result; 
    } 
    else if(first instanceof Byte) { 
     Byte _result = (Byte) first; 
     for(T next : it) 
      _result= (byte)(_result + (Byte)next); 
     return (T) _result; 
    } 
    else if(first instanceof Short) { 
     Short _result = (Short) first; 
     for(T next : it) 
      _result= (short)(_result + (Short)next); 
     return (T) _result; 
    } 
    else if(first instanceof java.math.BigInteger) { 
     java.math.BigInteger _result = (java.math.BigInteger) first; 
     for(T next : it) 
      _result=((java.math.BigInteger)next).add((BigInteger) next); 
     return (T) _result; 
    } 
    else if(first instanceof java.math.BigDecimal) { 
     java.math.BigDecimal _result = (java.math.BigDecimal) first; 
     for(T next : it) 
      _result=((java.math.BigDecimal)next).add((BigDecimal) next); 
     return (T) _result; 
    } 
    else { 
     throw new IllegalArgumentException(I18n._(String.format("Type %s not supported."), first.getClass())); 
    } 
} 
+1

Это будет работать только в том случае, если все числа одного типа, которые не очень понятны вне метода. Например, 'sum (Arrays.asList (1, 1.2, 3) 'приведет к' ClassCastException'. –

+1

, кстати, этот фрагмент кода показывает большую силу выражения Java –