0

I want to compute the arithmetic mean of any Collection of Integers or Doubles.

I have defined the following method:

public static double arithmeticMean(Collection<Number> collection) {

    for(Number element : collection)

        if (element.getClass().isInstance(Integer.class)) {

            Collection<Integer> intCollection = new ArrayList<>();
            for(Number number : collection)
                intCollection.add(number.intValue());
            return arithmeticMeanOfIntegers(intCollection);

        } else if (element.getClass().isInstance(Double.class)) {

            Collection<Double> doubleCollection = new ArrayList<>();
            for(Number number : collection)
                doubleCollection.add(number.doubleValue());
            return arithmeticMeanOfDoubles(doubleCollection);

        } 
    throw new IllegalArgumentException("Method 'arithmeticMean' only operates on integer or double types");      
}

To test the method, I create an ArrayList of Double, as follows:

private static ArrayList<Double> dataSet = getDataSet();

private static ArrayList<Double> getDataSet() {
    ArrayList<Double> dataSet = new ArrayList<>();
    for(int i = 1; i < 21; i++)
        dataSet.add(new Double(i));
    return dataSet;
}

But when I invoke the arithmeticMean method like this:

public static void main(String[] args) {
    System.out.println(arithmeticMean(dataSet));
    System.out.println(arithmeticMean((Collection<Number>) dataSet));
}

The first invocation results in the error:

The method arithmeticMean(Collection<Number>) in the type SimpleStats is not applicable for the arguments (ArrayList<Double>)

And the second invocation results in the error:

Cannot cast from ArrayList<Double> to Collection<Number>

After reading the Oracle Java Tutorials section on Collections, I do not understand why I can't pass an ArrayList object to a method expecting a Collection. ArrayList inherits from Collection and Double inherits from Number.

Can someone please explain?

Joala
  • 11
  • 4
  • It's not `ArrayList` and `Collection` it's `` and `` Generics are not covariant, you can't cast from one to the other. – markspace Mar 09 '19 at 20:35
  • It also might be: https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super since the OP is explicitly having problems with his method parameter. – markspace Mar 09 '19 at 20:39
  • Aside from the issue you are describing, the method itself doesn't really make sense. You aren't really looping over the collection, since you only look at the first element (and what if the elements are not all of the same type as the first); and there is no need to limit it to integer and double, or handle them separately, since all `Number` instances have a `.doubleValue()` method, so you can always calculate the `double` sum (and hence the mean). – Andy Turner Mar 09 '19 at 21:49

2 Answers2

0

I haven't tested this, but I think this works. Change the type of your method parameter:

public static double arithmeticMean(Collection<Number> collection) {

to

public static double arithmeticMean(Collection<? extends Number> collection) {

Edit: Since this worked, please read the answer to What is PECS?. It will help you understand more when and how to use generic wildcards.

markspace
  • 10,621
  • 3
  • 25
  • 39
0

From java tutorials:

In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.

You should use wildcards for this case like: Collection<? extends Number>

See more about Generics, Inheritance, and Subtypes

Ruslan
  • 6,090
  • 1
  • 21
  • 36