Java. Array type expected in lambda

voismager :

So, I've got an object constructor:

public Func(Function<Var[], Var<T>> function, Var... arguments) {
   // Function is a standart 1.8 class
   //...
   //secret stuff
}

I call it like that:

return new Func(new Function<Var[], Var>() {
        @Override
        public Var apply(Var[] args) {
            return instance.getAttribute(args[0].value());
        }

    }, arguments[0].unpack(instance)  // unpack(...) returns Var object
);

And it works. Now, my IDE (Intellij IDEA) suggests me to replace Function declaration with lambda. Okay, lets do it:

return new Func(
    args -> instance.getAttribute(args[0].value()), 
    arguments[0].unpack(instance)
);

Now I have an error on args:

Array type expected; found: 'java.lang.Object'

So, apparently args now is Object. Why? Is that a bug in IDE or what?

Entire code:

Template:

public class Template {
public static void main(String[] args) {
    SomeClass someClass = new SomeClass();
    System.out.println(someMethod(someClass).value());
}

private static class SomeClass {
    Var[] var = new Var[12];

    SomeClass() {
        var = new Var[12];

        for ( int i = 0; i < var.length; i++) {
            var[i] = new Var<>(i * 4);
        }
    }

    Var getAttribute(int index) {
        return var[index];
    }
}

public static Var someMethod(SomeClass instance) {
    return new Func(new Function<Var[], Var>() {
        @Override
        public Var apply(Var[] args) {
            return instance.getAttribute((int)args[0].value());
        }
    }, new Var(4));
}
}

Var.java:

public class Var<T> {
private T value;

public Var(T value) {
    this.value = value;
}

public T value() {
    return value;
}
}

Func.java:

public class Func<T> extends Var<T> {
private Function<Var[], Var<T>> function;
private Var[] args;

public Func(Function<Var[], Var<T>> function, Var... args) {
    super(null);

    this.function = function;
    this.args = args;
}

@Override
public T value() {
    return function.apply(args).value();
}
}
Topaco :

The error message appers also in the Eclipse-IDE:

The type of the expression must be an array type but it resolved to Object

I think it is not an IDE-bug, neither in IntelliJ nor in Eclipse. The Compiler needs for the processing of a lambda expression always a target type which is a functional interface. In the case of

 args -> instance.getAttribute((int)args[0].value()) 

the target type is determined by the first argument of the Func-constructor

 Function<Var[], Var<T>> function

However, this functional interface is a generic interface. Java compiles generics using type erasure which means the replacement of the generic parameter-types by the Object-type. Thus, the interface is compiled like

 interface Function {
     public Object apply(Object args);
 } 

and this is applied as target type. Thus, for args an Object-type instead of a Var[]-type is expected which results in an error message.

In case of an anonymous class this is different since more informations are provided for the determination of the target type.

 new Function<Var[], Var>(){...}

explicitly contains the type-information. Because of this args is expected of Var[]-type and no error message is shown.

There are two possibilities to fix the error:

1) In the getAttribut-method cast args explicitly to Var[], i.e. replace

 (int)args[0].value()

with

 (int)((Var[])args)[0].value()

or 2) Don't use a generic interface i.e. change the interface to

 interface Function {
     public Var apply(Var[] args);
 }

Then type information is preserved. Of course the rest of the code has to be adapted accordingly.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=103287&siteId=1