final
В параметрах метода и локальных переменных я считаю шум кода. Объявления методов Java могут быть довольно длинными (особенно с обобщениями) - больше нет необходимости их делать.
Если модульные тесты написаны правильно, присваивая параметры , что является «вредным» будет подобрано, поэтому он никогда не должен фактически быть проблемой. Визуальная ясность важнее, чем избегать возможной ошибки, которая не обнаружена , потому что ваши юнит-тесты имеют недостаточный охват.
Такие инструменты, как FindBugs и CheckStyle, которые можно настроить для разрыва сборки, если присваиваются параметры или локальные переменные, если вы серьезно заботитесь о таких вещах
Конечно, если вам нужно сделать их окончательными, например, потому что вы используете значение в анонимном классе, то нет проблем - это самое простое и чистое решение.
Помимо очевидного эффекта добавления дополнительных ключевых слов к вашим параметрам и, тем самым, ИМХО их маскировки, добавление окончательных параметров метода часто может сделать код в теле метода менее читабельным, что делает код хуже - «хорошим» кодом. должно быть максимально читабельным и максимально простым. Для надуманного примера, скажем, у меня есть метод, который должен работать без учета регистра.
Без final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
Просто. Clean. Все знают, что происходит.
Теперь с «окончательным», вариант 1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
Хотя создание параметров final
не позволяет кодеру добавлять код дальше от мысли о том, что он работает с исходным значением, существует равный риск того, что код, который находится ниже, может использовать input
вместо того lowercaseInput
, чего он не должен и который не может защитить, потому что вы можете ' т вывести его из сферы (или даже назначить null
на input
если бы даже помочь в любом случае).
С 'final', вариант 2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
Теперь мы просто создали еще больше шума в коде и представили снижение производительности из-за необходимости вызывать toLowerCase()
n раз.
С 'final', вариант 3:
public void doSomething(final String input) {
doSomethingPrivate(input.toLowerCase());
}
/** @throws IllegalArgumentException if input not all lower case */
private void doSomethingPrivate(final String input) {
if (!input.equals(input.toLowerCase())) {
throw new IllegalArgumentException("input not lowercase");
}
// do a few things with input
}
Поговорим о кодовом шуме. Это крушение поезда. У нас есть новый метод, обязательный блок исключений, потому что другой код может вызвать его неправильно. Дополнительные юнит-тесты для исключения. Все, чтобы избежать одной простой и ИМХО предпочтительной и безвредной линии.
Также существует проблема, заключающаяся в том, что методы не должны быть такими длинными, чтобы вы не могли легко визуально воспринять их и сразу увидеть, что имело место присвоение параметра.
Я действительно считаю хорошей практикой / стилем, что если вы назначаете параметр, вы делаете это каждый в начале метода, предпочтительно в первой строке или сразу после базовой проверки ввода, эффективно заменяя его для всего метода, что оказывает последовательный эффект в пределах метод. Читатели знают, что любое назначение должно быть очевидным (рядом с объявлением подписи) и в согласованном месте, что значительно смягчает проблему, которую пытается избежать добавление final. На самом деле я редко назначаю параметры, но если я это делаю, я всегда делаю это в начале метода.
Обратите внимание, что final
это не защищает вас так, как это может показаться на первый взгляд:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
не защищает вас полностью, если тип параметра не является примитивным или неизменным.