Я вважаю, що final
параметри методу та локальні змінні є кодовими шумами. Декларації методів Java можуть бути досить довгими (особливо з дженериками) - більше не потрібно їх робити.
Якщо одиничні тести написані належним чином, буде визначено "шкідливий" параметр, тому насправді це не повинно бути проблемою. Візуальна чіткість важливіша, ніж уникнення можливої помилки, яка не підбирається, оскільки тести вашого блоку мають недостатнє покриття.
Такі інструменти, як FindBugs і CheckStyle, які можуть бути налаштовані на розрив збірки, якщо призначається параметри або локальні змінні, якщо ви глибоко переймаєтесь такими речами.
Звичайно, якщо вам потрібно зробити їх остаточними, наприклад, тому що ви використовуєте значення в анонімному класі, то жодних проблем - це найпростіше чисте рішення.
Крім очевидного ефекту від додавання додаткових ключових слів до ваших параметрів, і тим самим IMHO маскує їх, додавання остаточних до параметрів методу часто може зробити код у тілі методу менш читабельним, що робить код гіршим - бути "хорошим", код повинні бути максимально читаними та максимально простими. Для надуманого прикладу скажіть, що у мене є метод, який потребує невідчутливої роботи.
Без final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
Простий. Чисто. Усі знають, що відбувається.
Тепер з 'остаточним', варіант 1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
Хоча введення параметрів final
зупиняє додавання кодеру коду далі від думки, що він працює з вихідним значенням, існує однаковий ризик, що input
замість нього може використовуватись код lowercaseInput
, який він не повинен і від якого не можна захистити, тому що ви можете ' т вивести його зі сфери (або навіть призначити null
на input
якби навіть допомогти в будь-якому випадку).
З "остаточним", варіант 2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
Тепер ми просто створили ще більший шум коду та ввели хит продуктивності щодо необхідності викликати toLowerCase()
n разів.
З "остаточним", варіант 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
насправді вас не захищає, як може здатися спочатку:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
не повністю захищає вас, якщо тип параметра не є примітивним або незмінним.