Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 generics and type inference issue

I'm trying to convert this:

static Set<String> methodSet(Class<?> type) {
    Set<String> result = new TreeSet<>();
    for(Method m : type.getMethods())
        result.add(m.getName());
    return result;
}

Which compiles just fine, to the more modern Java 8 streams version:

static Set<String> methodSet2(Class<?> type) {
    return Arrays.stream(type.getMethods())
        .collect(Collectors.toCollection(TreeSet::new));
}

Which produces an error message:

error: incompatible types: inference variable T has incompatible bounds
      .collect(Collectors.toCollection(TreeSet::new));
              ^
    equality constraints: String,E
    lower bounds: Method
  where T,C,E are type-variables:
    T extends Object declared in method <T,C>toCollection(Supplier<C>)
    C extends Collection<T> declared in method <T,C>toCollection(Supplier<C>)
    E extends Object declared in class TreeSet
1 error

I can see why the compiler would have trouble with this --- not enough type information to figure out the inference. What I can't see is how to fix it. Does anyone know?

like image 757
user1677663 Avatar asked Jan 14 '16 20:01

user1677663


People also ask

Does Java support type inference?

Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable.

Why generics are not supported to primitive data type?

Type safety is verified at compile time, and runtime is unfettered by the generic type system. In turn, this imposed the restriction that generics could only work over reference types, since Object is the most general type available, and it does not extend to primitive types.

Can generics take multiple type parameters?

A Generic class can have muliple type parameters.


1 Answers

The error message is not particularly clear but the problem is that you are not collecting the name of the methods but the methods themselves.

In other terms, you are missing the mapping from the Method to its name:

static Set<String> methodSet2(Class<?> type) {
    return Arrays.stream(type.getMethods())
                 .map(Method::getName) // <-- maps a method to its name
                 .collect(Collectors.toCollection(TreeSet::new));
}
like image 68
Tunaki Avatar answered Oct 07 '22 20:10

Tunaki