0

I have a client class which I cannot change.

List<Integer> list1= Arrays.asList(1,2,3);
System.out.println("Total sum is:"+sum(list1));
printlist(list1);
List<Double> list2=Arrays.asList(1.0,2.0,3.0);
System.out.println("Total sum is:"+sum(list2));
printlist(list2);

I have the business logic here

private static Object sum(List<? extends Number> list) {
    double sum = 0;
    for (Number i: list) {
        sum+=i.doubleValue();
    }     
    return sum;
}

So I want to return 6 for integer and 6.0 for a double. How can I do that? I am thinking to typecast sum as int or double based on type but due to type erasure all the info is lost. Can someone help me?

Alex Taylor
  • 8,343
  • 4
  • 25
  • 40
Harshal
  • 55
  • 7

3 Answers3

5

The objects in the list still have type information associated to them at run time. The only erased types are those of the generics (i.e. List in your example). The generics are checked at compile time, but are not maintained in the generated bytecode. That means you can use instanceof to check the contents of the collection:

private static Object sum(List<? extends Number> list) {
    Integer integerSum = 0;
    Double doubleSum = 0.0;
    boolean hasDouble = false;
    for (Number i: list) {
        if (i instanceof Integer) {
            integerSum += i.intValue();
        } else {
            doubleSum += i.doubleValue();
            hasDouble = true;
        }
    }
    if (hasDouble)
        return doubleSum + integerSum;
    return integerSum;
}

The code has some peculiarities to handle mixed lists, and doesn't handle Long, Short, Byte etc. properly.

Alex Taylor
  • 8,343
  • 4
  • 25
  • 40
4

Use 'instanceof"

     if( i instanceof Double) {
       System.out.println("param is a Double");
     }
     else if( i instanceof Integer) {
       System.out.println("param is an Integer");
    }
0

It is dangerous to assume that a Number subclass instance can be represented with double. To do this safely, you need to check for all possible types.

@SuppressWarnings("unchecked")
private static <T extends Number> T sum(List<T> list) {
    Objects.requireNonNull(list);

    if (list.isEmpty() || list.contains(null))
        throw new IllegalArgumentException();

    Class<T> clazz = (Class<T>) list.get(0).getClass();

    if (clazz == Integer.class) {
        return (T) (Integer) list.stream().mapToInt(i -> (Integer) i).sum();
    }
    else if (clazz == Double.class) {
        return (T) (Double) list.stream().mapToDouble(i -> (Double) i).sum();
    }
    /* And other Number subclass types */

    // Not possible if all types covered
    throw new IllegalStateException();
}

Here is a question/answer related to this.

Jai
  • 8,165
  • 2
  • 21
  • 52