Нужно ли указывать final для всех переменных которые не изменяются?

288
15 февраля 2022, 00:30

В книгах о Java написано, что если переменная не будет изменятся, то нужно указывать модификатор final. Но получается, что тогда этот модификатор нужно указывать почти всегда. Я просматривал репозитории с кодом на Java и заметил, что этот модификатор используется не так часто.

Ниже пример моей программы, здесь 100% переменных отмечены модификатором final.

Является ли это правильным? Соответствует ли это принципам чистого кода? Используете ли вы сами подобный подход? Если нет, то почему?

Пример (2)

import java.util.Scanner;
public class NoNumerals
{
    public static void main(String[] args) {
        final var input = new Scanner(System.in);
        final var phrase = input.nextLine();
        final String[] numbers = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
        final var updatedPhrase = new StringBuilder();
        for (final var word : phrase.split(" ")) {
            try {
                final int number = Integer.parseInt(word);
                if (number >= 0 && number <= 10) {
                        updatedPhrase.append(numbers[number]);
                } else {
                        updatedPhrase.append(word);
                }
            } catch (NumberFormatException nfe) {
                updatedPhrase.append(word);
            } finally {
                updatedPhrase.append(" ");
            }
        }
        System.out.print(updatedPhrase);
    }
}

Пример (1)

import java.util.Scanner;
public class Hovercraft
{
    public static void main(String[] args) {
        final Scanner input = new Scanner(System.in);
        final int sales = input.nextInt();
        final long hovercraftMonth = 10;
        final long hovercraftCosts = 2_000_000;
        final long hovercraftPrice = 3_000_000;
        final long insuranceMonth = 1_000_000;
        final long spentMonth = hovercraftMonth * hovercraftCosts + insuranceMonth;
        final long incomeMonth = sales * hovercraftPrice;
        if (incomeMonth > spentMonth) {
            System.out.print("Profit");
        } else if (incomeMonth < spentMonth) {
            System.out.print("Loss");
        } else {
            System.out.print("Broke Even");
        }
    }
}
Answer 1

этот модификатор нужно указывать почти всегда.

Зависит от стиля, принятого в компании. Почти всегда final указывают у статичных констант, или при работе с несколькими потоками. Видел стиль, когда final всегда указывался в параметрах функции, но редко.

Является ли это правильным?

Это и облегчит, и усложнит чтение кода. Лучше использовать final, если между объявлением поля и его последним использованием достаточно много строк. Если же строк несколько, то можно не указывать, т.к. это увеличит длину строки.

В вашем случае я бы оставил final у 1-х двух строк в 1-м примере, и у 1-х четырёх -- во 2-м примере.

Соответствует ли это принципам чистого кода?

Использование final для статичных констант и при работе с потоками -- соответствует. В остальных случаях -- опционально.

Используете ли вы сами подобный подход?

Я довольно часто указываю final, хотя чаще использую функциональные (или мультипарадигменные) языки, где практически нет переменных (есть константы). При работе с JS также предпочитаю const, т.к. использование const почти не увеличивает длину строки, т.е. не ухудшает читаемость. В Java часто указываю final у коллекций, чтоб быть уверенным, что коллекция не будет равна null.

Рекомендации Twitter на английском: 1 2

Попытался перевести:

Финальные поля полезны, потому что эти поля не могут быть переназначены. Когда дело доходит до проверки безопасности потока, можно будет не переживать хотя бы за изменяемость полей.

В общем случае, изменяемое статическое состояние является признаком плохого дизайна класса.

Изменяемые объекты требуют внимания -- вы должны убедиться, что те, кто может их изменять, не нарушают ожиданий других пользователей объекта, и что их безопасно изменять.

Из стиля Google: 1

Локальные переменные не должны быть стилизированы под константы.

Из требований Oracle 1

Любая локальная переменная, используемая, но не объявленная во вложенном классе, должна быть объявленна как final или должна быть финальной по факту.

Схожие вопросы на английском: 1 2 3 4 5 6 7

Пока что лень перевести полезные выдержки из них. Возможно, некоторые из ответов несколько субъективны.

Answer 2

Нет, указывать final везде где возможно не нужно. Данный модификатор нужен только для защиты констант, что используются много где в коде и не должны быть случайно изменены. А если какая-то переменная была объявлена в теле небольшой функции, то ты и так менять её не будешь. Модификаторы - это страховка от ошибок программиста. В код они вроде никак не компилируются, однако при компиляции, если нарушено правило модификатора, дают ошибку

READ ALSO
dynamic binding

dynamic binding

читаю "Философию Java" ЭккеляКак-то к сожалению он сложно описывает некоторые моменты, и один из таких: Динамическое связывание

161
Отсортировать Map&lt;Event, List&lt;Data&gt;&gt; по значению List.size

Отсортировать Map<Event, List<Data>> по значению List.size

я решил вопрос через создание дополнительной мапы и выглядит это жутко

119
return не действует на наследника (Java)

return не действует на наследника (Java)

Доброе время сутокЯ столкнулся с такой проблемой, что у меня есть родительский класс и его наследник

115