@Volokoron

Область видимости/замыкание лямбда в Java?

public void m() {
        Human human1 = new Human(25, "Sam");
        Human human2 = new Human(25, "Max");
        Runnable r1 = () -> {
            System.out.println(human1.age + "-" + human2.age); //Почему не происходит ошибка?!
        };
        human1.age = 100;
        human2.age = 100;
        
        int var  = human1.age;
        Runnable r2 = () -> {
            System.out.println(var);
             //Ошибка компилятора
            //Variable (var) used in lambda expression should be final or effectively final
        };
        var = 12;
}

Доброго дня!
Почему первом случае не происходит ошибки effectively final/final?
  • Вопрос задан
  • 548 просмотров
Решения вопроса 1
xez
@xez Куратор тега Java
TL Junior Roo
Дело в том, что human1 и human2 - действительно EffectivelyFinal.
Эти переменные содержат ссылку на объект. Эта ссылка не изменяется.
Переменная var - очевидно, не EffectivelyFinal.
Попробуйте присвоить human1 новый объект и увидите такое же предупреждение компилятора.

Цитата из книги «Современный язык Java. Лямбда-выражения, потоки и функциональное программирование»:

Возможно, вы слышали термин «замыкание» (closure, не путайте с языком программи- рования Clojure) и вам интересно, соответствуют ли его определению лямбда-выражения. На более формальном языке замыкание — экземпляр функции с возможностью без всяких ограничений обращаться к нелокальным по отношению к этой функции переменным. Например, замыкание можно передать как аргумент другой функции. Оно может также обращаться к переменным, объявленным вне его области видимости, и изменять их значения. Лямбда-выражения и анонимные классы Java 8 похожи на замыкания: их можно передавать в качестве аргументов методам, они могут обращаться к переменным вне своей области видимости. Но на них налагается ограничение: они не могут модифицировать содержимое локальных переменных метода, в котором описаны. Эти переменные фактически являются неизменяемыми (final). Удобно считать, что лямбда-выражения замыкают значения, а не переменные. Как уже объяснялось ранее, это ограничение связано с тем, что локальные переменные располагаются в стеке и неявным образом ограничены своим потоком выполнения. Если разрешить захват изменяемых локальных переменных, это приведет к открытию новых потоконебезопасных, а значит, нежелательных возможностей (переменные экземпляра в этом смысле допустимы, поскольку хранятся в куче, совместно используемой разными потоками выполнения).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы