Як зазначається в коментарях, дещо з цього стає неважливим у Java 8, де це final
може бути неявним. В анонімному внутрішньому класі або лямбда-виразі можна використовувати лише ефективно остаточну змінну.
В основному це пов'язано з тим, як Java управляє закриттями .
Коли ви створюєте екземпляр анонімного внутрішнього класу, будь-які змінні, які використовуються в цьому класі, копіюють свої значення через автогенерований конструктор. Це дозволяє уникнути компілятора, який повинен автогенерувати різні додаткові типи, щоб утримувати логічний стан "локальних змінних", як, наприклад, компілятор C # ... (Коли C # захоплює змінну в анонімну функцію, вона дійсно фіксує змінну - Закриття може оновлювати змінну таким чином, як це бачиться основним елементом методу, і навпаки.)
Оскільки значення було скопійовано в екземпляр анонімного внутрішнього класу, буде дивно, якби змінна могла бути модифікована рештою методу - у вас може виникнути код, який, здається, працює із застарілою змінною ( адже це фактично те, що буде ... ви працювали з копією, зробленою в інший час). Так само, якщо ви могли вносити зміни в анонімний внутрішній клас, розробники можуть очікувати, що ці зміни будуть помітні в тілі методу, що додає.
Здійснення змінної остаточної видаляє всі ці можливості - оскільки значення взагалі неможливо змінити, вам не потрібно турбуватися про те, чи будуть видимі такі зміни. Єдиний спосіб дозволити методу та анонімному внутрішньому класу побачити зміни один одного - це використовувати змінений тип деякого опису. Це може бути сам клас, що додається, масив, тип змінної обгортки ... все подібне. В основному це трохи схоже на спілкування між одним методом та іншим: зміни, внесені до параметрів одного методу, його виклик не бачить, але зміни, внесені до об'єктів, на які посилаються параметри, бачуться.
Якщо вас зацікавило більш детальне порівняння між закриттями Java та C #, у мене є стаття, яка детальніше розглядає її. У цій відповіді я хотів зосередитись на стороні Java :)