final
W parametrach metody i zmiennych lokalnych uważam szum za kod. Deklaracje metod Java mogą być dość długie (szczególnie w przypadku generyków) - nie trzeba ich już robić.
Jeśli testy jednostkowe są napisane poprawnie, przypisując do parametrów, które jest „szkodliwe” będzie podniósł, więc nigdy nie powinny faktycznie być problemem. Wizualna przejrzystość jest ważniejsza niż unikanie możliwego błędu, który nie został wykryty, ponieważ twoje testy jednostkowe mają niewystarczający zasięg.
Narzędzia takie jak FindBugs i CheckStyle, które można skonfigurować tak, aby przerywały kompilację, jeśli przypisano parametry lub zmienne lokalne, jeśli bardzo zależy ci na takich rzeczach.
Oczywiście, jeśli trzeba , aby je ostateczna, na przykład dlatego, że używasz wartości w anonimowej klasy, wtedy nie ma problemu - to najprostsza najczystsze rozwiązanie.
Oprócz oczywistego efektu dodania dodatkowych słów kluczowych do parametrów, a tym samym kamuflowania ich przez IMHO, dodanie finału do parametrów metody może często spowodować, że kod w treści metody stanie się mniej czytelny, co pogorszy kod - aby był „dobry”, kod musi być tak czytelny i jak najprostszy. Dla wymyślonego przykładu, powiedzmy, że mam metodę, która musi rozróżniać przypadki bez rozróżnienia.
Bez final
:
public void doSomething(String input) {
input = input.toLowerCase();
// do a few things with input
}
Prosty. Czysty. Wszyscy wiedzą, co się dzieje.
Teraz z „ostateczną” opcją 1:
public void doSomething(final String input) {
final String lowercaseInput = input.toLowerCase();
// do a few things with lowercaseInput
}
Podczas gdy parametry powodują, że final
koder nie dodaje kodu dalej, niż myśli, że pracuje z pierwotną wartością, istnieje jednakowe ryzyko, że kod użyty niżej może użyć input
zamiast tego lowercaseInput
, czego nie powinien i przed którym nie może się zabezpieczyć, ponieważ można „ t wyjąć z zakresu (lub nawet przypisać null
do input
jeżeli byłoby nawet pomóc w każdym razie).
Z „ostatecznym” wariantem 2:
public void doSomething(final String input) {
// do a few things with input.toLowerCase()
}
Teraz stworzyliśmy jeszcze więcej szumu kodu i wprowadziliśmy hit wydajności związany z koniecznością wywoływania toLowerCase()
n razy.
Z „ostatecznym” wariantem 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
}
Mów o szumie kodu. To jest wrak pociągu. Mamy nową metodę, wymagany blok wyjątków, ponieważ inny kod może wywołać ją niepoprawnie. Więcej testów jednostkowych w celu uwzględnienia wyjątku. Wszystko po to, by uniknąć jednej prostej, preferowanej i nieszkodliwej linii IMHO.
Istnieje również problem polegający na tym, że metody nie powinny być tak długie, aby nie można było łatwo ich wizualnie przyjąć i na pierwszy rzut oka wiedzieć, że miało miejsce przypisanie parametru.
Myślę, że dobrą praktyką / stylem jest to, że jeśli przypisujesz do parametru, robisz to na początku metody, najlepiej w pierwszym wierszu lub bezpośrednio po podstawowym sprawdzaniu danych wejściowych, skutecznie zastępując go dla całej metody, co ma spójny efekt w metoda. Czytelnicy wiedzą, że można oczekiwać, że każde zadanie będzie oczywiste (w pobliżu deklaracji podpisu) i w spójnym miejscu, co znacznie złagodzi problem, którego próbuje uniknąć dodania ostatecznego. Właściwie rzadko przypisuję parametry, ale jeśli to robię, zawsze robię to na początku metody.
Zauważ też, że final
tak naprawdę cię nie chroni, jak mogłoby się początkowo wydawać:
public void foo(final Date date) {
date.setTime(0);
// code that uses date
}
final
nie chroni cię całkowicie, chyba że typ parametru jest prymitywny lub niezmienny.