Java лямбда-выражение с захватом локальной переменной - PullRequest
1 голос
/ 02 октября 2019

Причина, по которой локальная переменная является окончательной или фактически окончательной, из-за проблем с валютой. В спецификации jls 8 говорится следующее:

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

Все хорошо и мило, но я провел небольшой эксперимент. Что если я синхронизирую метод, это исключит возможность динамического изменения локальной переменной, потому что я гарантированно, что только один поток может выполнить этот код. Но компиляция выдавала ошибку, говоря, что она должна быть окончательной или эффективно окончательной.

Правильна ли логика?

Рассмотрим следующий код:

    public synchronized void capture() {

        int localVariable = 100;

        Interf i = (text) -> System.out.println(text + localVariable);

        i.m1("This local variable is: ");

        localVariable = 1000;
    }
}

Ответы [ 2 ]

0 голосов
/ 02 октября 2019

Но компиляция выдавала ошибку, говоря, что она должна быть окончательной или эффективно окончательной.

Это потому, что это происходит согласно правилам. Нет, нет, но нет;не имеет значения, действительно ли вы защитились от всех проблем параллелизма или нет - если он не является окончательным, он не скомпилируется.

В вашем упрощенном примере здесь, вероятно, все в порядке. Однако синхронизировать метод не имеет значения, так как локальные переменные всегда будут привязаны к их вызову для каждого потока. Это проблемы с многопоточностью в контексте самого метода, о которых беспокоится компилятор, и это может легко произойти с использованием лямбда-выражений (которые могут быть выполнены некоторое произвольное время в будущем, после того, как состояние неконечной переменной может изменитьсяи, если это так, не совсем понятно, какое состояние следует использовать - начальное состояние или обновленное состояние.)

0 голосов
/ 02 октября 2019

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

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