Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Функциональная лямбда Java-8 по сравнению с явным выражением сообщает об ошибке компилятора

Автор вопроса: DitzОтветов: 2

Теперь, используя java-8, я превратил явное объявление в лямбда-выражение и получил ошибку компилятора. Так что подозревайте, что это "ошибка" текущей версии java-8 (b105).

Пример кода определяет два объекта Function с использованием лямбда-выражения и без него. Оба ретранслируют предикат, который используется этими функциями. В то время как традиционная реализация работает, лямбда-версия сообщает об ошибке:

Java: переменная fileExists могла быть не инициализирована

Это не совсем неправильно, но предикат актуален, если функция используется, а не если сама функция создается (поскольку явная версия работает хорошо). Должен ли я сообщить об ошибке (у кого-то есть ссылка?) или я что-то пропустил?

public class FileOpener {

public FileOpener(Predicate<File> fileExists) {
    this.fileExists = fileExists;
}

final Predicate<File> fileExists;

final Function<File, FileInputStream> openLambda = file -> {
    try {
        return fileExists.test(file) ? new FileInputStream(file) : null;
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
};

// this version compiles
final Function<File, FileInputStream> openFunction = new Function<File, FileInputStream>() {
    @Override
    public FileInputStream apply(File file) {
        try {
            return fileExists.test(file) ? new FileInputStream(file) : null;
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
};

}

  • Прежде чем сообщать об ошибке, я бы (а) обновился до последней версии и (б) спросил в специальном списке рассылки, может быть, в этом: mail.openjdk.java.net/mailman/listinfo/jdk8-dev Поведение для лямбды кажется разумным, потому что это захватывающая лямбда и, вероятно, нужно знать о значение его параметра при его построении. assylias 15.10.2013
  • И где инициализируется fileExists? Разве поля не инициализируются до конструктора? Edwin Dalorzo 16.10.2013
  • @assylias: захват применяется только к локальным переменным. Поскольку это не метод, локальные переменные отсутствуют. newacct 16.10.2013
  • @Edwin: fileExists инициализируется в конструкторе и, следовательно, ПОСЛЕ openLambda. Вопрос в том, является ли это серьезной проблемой, как сообщает java8. Ditz 16.10.2013
  • @Ditz Дело в том, что openLambda является полем экземпляра, поэтому во время создания объекта оно оценивается ДО конструктора, поэтому fileExists в этот момент не инициализируется. Edwin Dalorzo 16.10.2013
  • @Ditz: Эдвин Далорзо прав. fileExists не инициализируется при инициализации openLambda. newacct 16.10.2013

javajava-8lambda

Ответы

Ответ 1 · рейтинг 1 · Holger

Сообщение об ошибке правильное, как было указано Эдвином Далорзо. Здесь важен порядок инициализации. Сначала выполняются инициализаторы полей в порядке их появления в исходном файле, затем конструктор. Лямбды, ссылающиеся на переменные, захватывают переменные, а в случае конечных переменных (и всех локальных переменных) они фиксируют фактическое значение переменной, которая требует инициализации переменной. Это соответствует спецификации языка Java и не изменилось в Java 8:

class SimpleTest
{
  SimpleTest()
  {
    first="a string";
  }
  final String first;
  String second=first;
}

показывает точно такое же поведение в версии до Java 8.

Ответ 2 · Anna Zubenko

Я попробовал ваш код и немного поиграл с ним... Оказывается, если вы удалите модификатор final из fileExists, все компилируется и работает нормально, так что, возможно, обсуждение в комментариях не на 100% точно, fileExists на самом деле можно инициализировать в конструкторе . Похоже, компилятор не определяет, что инициализация действительно происходит (ммм?).

Это может быть ошибка... Единственное, что я нашел для ошибок, это http://bugreport.sun.com/bugreport/ (несмотря на SUN в названии, на самом деле ведет на сайт Oracle).

P.S.: пользуюсь b111 от 10 октября.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы