2

When I try to set a parameter as extending number using wildcards as shown in the code below -

import java.util.*;

class Try {
    public static void main(String [] args) {
        List <Integer>a = new ArrayList<>();
        a.add(1);
        a.add(2);
        a.add(3);
        System.out.println(foo(a));
    }

    public static double foo(List<? extends Number> list) {
        double x = 0.0;
        for (Object e : list)
            x += (Integer) e;
        return x;
    }
}

It compiles fine. However, If i do the same using a generic type, as shown here -

import java.util.*;

class Try {
    public static void main(String [] args) {
        List <Integer>a = new ArrayList<>();
        a.add(1);
        a.add(2);
        a.add(3);
        System.out.println(foo(a));
    }

    public static <T extends Number> double foo(List<T extends Number> list) {
        double x = 0.0;
        for (Object e : list)
            x += (Integer) e;
        return x;
    }
}

I get the following syntax error -

Try.java:12: error: > expected
    public static <T extends Number> double foo(List<T extends Number> list) {
                                                       ^
Try.java:12: error: ')' expected
    public static <T extends Number> double foo(List<T extends Number> list) {
                                                              ^
Try.java:12: error: ';' expected
    public static <T extends Number> double foo(List<T extends Number> list) {
                                                                     ^
Try.java:12: error: <identifier> expected
    public static <T extends Number> double foo(List<T extends Number> list) {
                                                                           ^
4 errors

Why does the second case give me an error? What is the difference between generics and wildcards in this case?

Nikhil Prabhu
  • 1,072
  • 3
  • 12
  • 24
  • "It compiles fine" but doesn't isn't type safe. Try calling `foo(Array.asList(0.0))`. That also compiles fine, but fails at runtime. – Andy Turner Nov 07 '16 at 06:59
  • 1
    Use `List` instead. It's already a bounded type variable. (But this doesn't make it type safe though). – Andy Turner Nov 07 '16 at 07:00
  • Possible duplicate of [What is the difference between bounded wildcard and type parameters?](http://stackoverflow.com/questions/1750273/what-is-the-difference-between-bounded-wildcard-and-type-parameters) – Sikorski Nov 07 '16 at 07:02

2 Answers2

1

What you wrote is invalid syntax. This is what you intended:

public static <T extends Number> double foo(List<T> list) {

That is, the extends belongs to the type token definition, not the type declaration in the method parameter list.

janos
  • 120,954
  • 29
  • 226
  • 236
  • 2
    Why isn't wildcards type-safe considering that ? extends Number, thus guaranteeing that all types passed are subtypes of Number. Does using generics do something more than this? – Nikhil Prabhu Nov 07 '16 at 07:07
  • With the wildcards version, you could pass in a list that has a mixture of subtypes of Number in it, that is, not homogenous. With three generic version there can be only homogenous objects – janos Nov 07 '16 at 07:13
  • 2
    "The main difference between this and your first wildcard version is that this is type-safe." There's no difference between this and the first version, because `T` is not used beyond this parameter declaration. This version would allow you to use `T` as the type of the enhanced for loop variable, for example. But even then, there is no type safety advantage. – Andy Turner Nov 07 '16 at 07:33
  • This is completely identical to the first wildcard version. It cannot be "type-safe" if the other one isn't. – newacct Nov 09 '16 at 01:50
0

Assuming that in your second piece of code you meant this:

public static <T extends Number> double foo(List<T> list)

There is no difference between the two declarations. Any type that can be passed to one function signature can be passed to the other, and vice versa. Every possible type List<T> where T is a non-strict subtype of Number, is a subtype of List<? extends Number>. And List<? extends Number> can be captured into List<T> with T extends Number. So the two are completely equivalent.

newacct
  • 119,665
  • 29
  • 163
  • 224