Визначення аргументів методу Java як остаточних


92

Яка різниця finalміж кодом нижче. Чи є якась перевага в оголошенні аргументів як final.

public String changeTimezone( Timestamp stamp, Timezone fTz, Timezone toTz){  
    return ....
}

public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
        final Timezone toTz){
    return ....
}

4
Існують аналізатори коду, які попереджають про повторне використання або перепризначення параметра. (Те саме для локальних змінних) IMHO, Це кращий спосіб вловити такі параметри, якщо ви вважаєте, що їх зміна небажана.
Пітер Лорі


Я вважаю, що Java повинна робити всі аргументи методу введення фінальними за замовчуванням. І тоді, якщо я хочу змінити посилання, мені доведеться це робити вручну. Таким чином, фактор вини запобігає багатьом таким випадкам.
Сід

Відповіді:


131

Оскільки параметр формального методу є локальною змінною, ви можете отримати до них доступ із внутрішніх анонімних класів, лише якщо вони оголошені як остаточні.

Це позбавляє вас від оголошення іншої локальної кінцевої змінної в тілі методу:

 void m(final int param) {
        new Thread(new Runnable() {
            public void run() {
                System.err.println(param);
            }
        }).start();
    }

27
+1: це важливий випадок використання та єдиний раз, коли він вам потрібен . (В інший час це лише питання того, що зручно допомогти програмісту.)
Donal Fellows

3
Чи можу я запитати міркування за цим?
KodeWarrior

21
Більше не потрібно з Java 8.
Аміт Парашар

3
@simgineer прочитати тут: stackoverflow.com/questions/28408109 / ...
PeterMmm

3
@AmitParashar Правда, але Java 8 просто рятує вас від необхідності використовувати ключове слово "final" кожного разу, коли вам доводиться використовувати змінну у внутрішньому класі ... Реальність така, що компілятор просто робить остаточну неявну, ви все ще потрібна змінна, щоб вона була ефективно остаточною ... Отже, ви все одно отримуєте помилку часу компіляції, якщо спробуєте призначити її пізніше! Java 8 : SNEAK 100 :)
варун

38

Витяг із кінцевого слова з кінцевого ключового слова

Кінцеві параметри

Наступний зразок оголошує кінцеві параметри:

public void doSomething(final int i, final int j)
{
  // cannot change the value of i or j here...
  // any change would be visible only inside the method...
}

Тут використовується final, щоб переконатися, що два індекси i та j випадково не будуть скинуті методом. Це зручний спосіб захистити від підступної помилки, яка помилково змінює значення ваших параметрів. Взагалі кажучи, короткі методи є кращим способом захисту від цього класу помилок, але кінцеві параметри можуть бути корисним доповненням до вашого стилю кодування.

Зверніть увагу, що кінцеві параметри не вважаються частиною сигнатури методу, і компілятор ігнорує їх під час розв'язання викликів методів. Параметри можна оголосити остаточними (чи ні), не впливаючи на те, як метод замінений.


18
Для цього прикладу може бути краще використовувати об’єкти, а не примітиви, оскільки примітивні зміни завжди будуть видно лише всередині методу. А у випадку з об’єктами ви все одно можете їх змінити. Ви просто не можете вказати на новий об’єкт. Насправді, я зараз замислююся, final насправді нічого не змінює порівняно із залишенням, окрім збереження декларації змінної за допомогою AIC і того, щоб компілятор вказував на випадкові зміни параметрів, які ви не хотіли змінювати з якихось причин .
Роб Грант

27

Остаточний заважає вам присвоювати нове значення змінній, і це може бути корисним для лову помилок. У стилістичному плані ви можете залишити незмінними отримані параметри та призначити їх лише локальним змінним, тому final допоможе застосувати цей стиль.

Потрібно визнати, що я рідко згадую використовувати final для параметрів, можливо, мені слід.

public int example(final int basicRate){
    int discountRate;

    discountRate = basicRate - 10;
    // ... lots of code here 
    if ( isGoldCustomer ) {
        basicRate--;  // typo, we intended to say discountRate--, final catches this
    }
    // ... more code here

    return discountRate;
}

1
Чудовий приклад того, як оголошення аргументів кінцевими може бути корисним. Я прихильний до цього, але вони також пропонують 3+ параметри.
JoseHdez_2

14

Це не має великої різниці. Це просто означає, що ви не можете писати:

stamp = null;
fTz = new ...;

але ви все ще можете написати:

stamp.setXXX(...);
fTz.setXXX(...);

В основному це натяк програмісту з обслуговування, який слідує за вами, що ви не збираєтеся призначати нове значення параметру десь посередині вашого методу, де це не очевидно і, отже, може спричинити плутанину.


3

Кінцеве ключове слово, яке використовується для параметрів / змінних у Java, позначає посилання як остаточне. У разі передачі об'єкта іншому методу система створює копію посилальної змінної та передає її методу. Позначаючи нові посилання остаточними, ви захищаєте їх від перепризначення. Іноді це вважається гарною практикою кодування.


1
Я повинен додати щось: якщо параметри примітивні, я не бачу ніяких відмінностей. Крім того, якщо параметри є Колекціями (список об'єктів ...), додавання final не може перешкодити їх модифікації.
Sam003

1
Незмінність - завжди бажана риса. Java не має його прямо з коробки. Встановлення змінних остаточними, принаймні, забезпечує цілісність посилань.
Сід

1
Я згоден. Але якщо ми дійсно хочемо досягти незмінності об’єктів, ми могли б спробувати зробити глибокий клон.
Sam003

2

Для тіла цього методу finalключове слово буде перешкоджати випадковому перепризначенню посилань на аргументи, що дасть помилку компіляції у цих випадках (більшість середовищ розробки середовища скаржиться відразу). Деякі можуть стверджувати, що використання finalзагалом, коли це можливо, пришвидшить процес, але це не так у останніх JVM.


2

Перелічено дві переваги:

1 Позначення аргументу методу як остаточного запобігає перепризначенню аргументу всередині методу

З вашого прикладу

    public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
            final Timezone toTz){
    
    // THIS WILL CAUSE COMPILATION ERROR as fTz is marked as final argument

      fTz = Calendar.getInstance().getTimeZone();     
      return ..
    
    }

У складному методі позначення аргументів як остаточних допоможе випадковому тлумаченню цих аргументів як методів локальних змінних, і перепризначення як компілятор позначить ці випадки, як показано в прикладі.

2 Передача аргументу анонімному внутрішньому класу

Оскільки параметр формального методу є локальною змінною, ви можете отримати до них доступ із внутрішніх анонімних класів, лише якщо вони оголошені як остаточні.


1

- Раніше (до Java 8 :-))

Явне використання ключового слова "final" вплинуло на доступність змінної методу для внутрішніх анонімних класів.

- У сучасній мові (Java 8+) немає необхідності в такому використанні:

Java представила "ефективно кінцеві" змінні. Місцеві змінні та параметри методу вважаються остаточними, якщо код не передбачає зміни значення змінної. Отже, якщо ви бачите таке ключове слово в Java8 +, ви можете припустити, що воно непотрібне. Введення "фактично остаточного" змушує нас вводити менше коду при використанні лямбда.


0

Це просто конструкція на Java, яка допоможе вам визначити контракт і дотримуватися його. Подібна дискусія тут: http://c2.com/cgi/wiki?JavaFinalConsideredEvil

До речі - (як говорить twiki), позначення аргументів як остаточних, як правило, зайве, якщо ви дотримуєтесь хороших принципів програмування і, отже, зробили перепризначення / перевизначення посилання на вхідний аргумент.

У гіршому випадку, якщо ви перевизначите посилання на аргументи, це не вплине на фактичне значення, передане функції, оскільки передано лише посилання.


0

Я взагалі кажу про позначення змінних та полів кінцевими - це стосується не лише аргументів методу. (Фінальні методи позначення / класи - це зовсім інша справа).

Це послуга читачам / майбутнім, хто підтримує ваш код. Разом із розумним іменем змінної корисно і заспокоює читача вашого коду побачити / зрозуміти, що представляють собою змінні, про які йде мова - і заспокоює читача, що всякий раз, коли ви бачите змінну в тому ж обсязі, значення залишається те саме, тому (і) йому не потрібно чесати голову, щоб завжди з’ясувати, що змінна означає у кожному контексті. Ми спостерігали занадто багато зловживань "повторного використання" змінних, що ускладнює розуміння навіть короткого фрагмента коду.


-3

Заключне ключове слово заважає вам присвоїти параметру нове значення. Я хотів би пояснити це на простому прикладі

Припустимо, у нас є метод

method1 () {

Date dateOfBirth = нова дата ("1/1/2009");

метод2 (dateOfBirth);

метод3 (dateOfBirth); }

public mehod2 (Date dateOfBirth) {
....
....
....
}

public mehod2 (Date dateOfBirth) {
....
....
....
}

У наведеному вище випадку, якщо "dateOfBirth" призначено нове значення в методі2, це призведе до неправильного виводу з методу3. Оскільки значення, яке передається методу3, є не таким, як було до передачі методу2. Отже, щоб уникнути, це остатнє ключове слово використовується для параметрів.

І це також одна з найкращих практик кодування Java.


5
Це не зовсім правильно. Навіть якщо аргумент dateOfBirth змінити на інше значення в method2 (), це не вплине на method2 (), оскільки Java передається за значенням, а не за посиланням.
Фло
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.