Джава.Тип массива ожидается в лямбде - PullRequest
0 голосов
/ 18 октября 2018

Итак, у меня есть конструктор объекта:

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

Я называю это так:

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
);

И это работает.Теперь моя IDE (Intellij IDEA) предлагает мне заменить объявление функции лямбда-выражением.Хорошо, давайте сделаем это:

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

Теперь у меня ошибка на args:

Ожидается тип массива;найдено: 'java.lang.Object'

Итак, очевидно, args теперь является объектом.Зачем?Это ошибка в IDE или что?

Весь код:

Шаблон:

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();
}
}

1 Ответ

0 голосов
/ 21 октября 2018

Сообщение об ошибке появляется также в Eclipse-IDE:

Тип выражения должен быть типом массива, но оно разрешено в Object

Я думаю, что этоне является ошибкой IDE, ни в IntelliJ, ни в Eclipse.Компилятору нужен для обработки лямбда-выражения всегда тип цели , который является функциональным интерфейсом.В случае

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

целевой тип определяется первым аргументом конструктора Func

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

Однако этот функциональный интерфейс является универсальным интерфейсом.Java компилирует обобщенные типы, используя стирание типа , что означает замену обобщенных типов параметров типом объекта.Таким образом, интерфейс компилируется как

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

, и это применяется в качестве целевого типа.Таким образом, для аргументов ожидается тип Object вместо типа Var [], что приведет к сообщению об ошибке.

В случае анонимного класса это не так, поскольку для определениятип цели

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

явно содержит информацию о типе.Из-за этого ожидаются аргументы типа Var [], и сообщение об ошибке не отображается.

Существует две возможности исправить ошибку:

1) В методе getAttribut приводить аргументы явнона Var [], т.е. замените

 (int)args[0].value()

на

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

или 2) Не используйте универсальный интерфейс, т.е. измените интерфейс на

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

Тогда информация о типе сохраняется.Конечно, остальная часть кода должна быть соответствующим образом адаптирована.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...