Почему переменные внутри цикла foreach java8 должны быть окончательными?

Я повторяю список массивов в цикле Java 7 и Java 8 forEach. Ядро Java 8 требует, чтобы переменная внутри цикла была окончательной. Например,

    List<String> testList = Arrays.asList( "apple", "banana", "cat", "dog" );

    int count = 0;

    testList.forEach( test -> {
        count++; // compilation Error : Local variable count defined in an enclosing scope must be final or effectively final
    });

    for( String test: testList ) {
        count++; // No Error
    } 

Может кто-нибудь объяснить, почему это так? Это недостаток Java 8?

Ответы

Ответ 1

Модель памяти Java имеет очень важное свойство: она гарантирует, что локальные переменные и параметры метода никогда нельзя перезаписывать другим потоком. Это добавляет много безопасности в многопоточное программирование. Однако, когда вы создаете лямбду (или анонимный класс), никто не знает, как он будет использоваться. Его можно передать в другой поток для выполнения (например, если вы используете parallelStream().forEach(...)). Возможно ли изменить локальную переменную, что важное свойство будет нарушено. Не то, что разработчики языка Java пожертвовали бы.

Обычно, когда вы используете lambdas, вы пытаетесь программировать функционально. Но в функциональном программировании изменяемые переменные считаются плохой практикой: лучше назначать каждую переменную только один раз. Поэтому попытка изменить локальную переменную на самом деле пахнет. Используйте различные методы сокращения потока вместо forEach, чтобы создать хороший функциональный код.