简体   繁体   English

我是否需要为 Java 中的所有不可变变量指定 «final» 修饰符?

[英]Do I need to specify «final» modifier for ALL immutable variables in Java?

In one Java book I read “In general, it's a good idea to always declare variables as final, and constant fields as static final, if they don't need to be reassigned“ .在我读过的一本 Java 书中, “一般来说,如果不需要重新分配变量,则始终将变量声明为 final,将常量字段声明为 static final 是个好主意” I started to follow this advice.我开始遵循这个建议。 But when I started to code, I discovered that almost all my variables are immutable.但是当我开始编码时,我发现几乎所有的变量都是不可变的。 But using the keyword «final» makes lines longer and as result it is harder to read the code and this goes against the principles of clean code.但是使用关键字«final»会使行变得更长,因此更难阅读代码,这违背了干净代码的原则。 So here are my questions:所以这里是我的问题:

  1. Is it a good practice to make all immutable variables «final»?将所有不可变变量设为“final”是一个好习惯吗?
  2. Do you use «final» modifier for all your immutable variables in your programs?您是否对程序中的所有不可变变量使用 «final» 修饰符?
  3. If not, when do you use «final» and when do you skip using this keyword?如果没有,你什么时候使用«final»,什么时候跳过使用这个关键字?

Here is an example of my program from code coach repository .这是我的代码教练存储库中的程序示例。 All variables are final.所有变量都是最终的。 The same situation almost in all other programs in the repository.同样的情况几乎出现在存储库中的所有其他程序中。

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);
            }
            updatedPhrase.append(" ");
        }
        System.out.print(updatedPhrase);
    }
}

There are multiple reasons you may want to declare a variable final , including:您可能想要声明变量final原因有多种,包括:

  • Simplicity - a final variable must be initalised, and cannot be re-assigned.简单性- 必须初始化最终变量,并且不能重新分配。 Hence, a section of code frees the reader from having to reason about mutable state or uninitialised variables.因此,一段代码使读者不必对可变状态或未初始化的变量进行推理。 The compiler will prevent both.编译器将阻止两者。 This means that a final variable will also prevent bugs such as accidental re-assignment or accidental use of an uninitialised class member.这意味着 final 变量还将防止错误,例如意外重新分配或意外使用未初始化的类成员。

  • Self-documenting - a variable or class member declared final is an explicit signal to the user of the intent that the variable should never be re-assigned.自记录- 声明为 final 的变量或类成员是向用户明确表示永远不应重新分配变量的意图的信号。

  • Thread-safety - a final reference can safely be read without synchronisation.线程安全- 无需同步即可安全读取最终引用。 An immutable object (ie all member fields are final, and either primitive or references to other immutable objects), can be concurrently accessed without synchronisation.一个不可变对象(即所有成员字段都是最终的,并且可以是原始对象或对其他不可变对象的引用),可以在没有同步的情况下并发访问。

  • Compiler required use cases - only effectively final variables can be referred to in try-with-resources expressions, or captured by lambdas.编译器所需的用例- 只有有效的最终变量才能在 try-with-resources 表达式中引用,或由 lambdas 捕获。 For an overview of the difference beeween final , effectively final , and implicitly final variables, refer to the following this answer .有关 beeween final有效 final隐式 final变量之间差异的概述,请参阅以下此答案

As an aside, I've noticed that developers with experience using "pure functional" languages (such as F# and Haskell) will tend to favour liberal use of final .顺便说一句,我注意到有使用“纯函数”语言(例如 F# 和 Haskell)经验的开发人员倾向于自由使用final In these languages, all values are "immutable by default".在这些语言中,所有值都是“默认不可变的”。 When coming back to Java after working with these languages, I find myself missing the simplicity and freedom afforded by the "immutable by default" approach.在使用这些语言后回到 Java 时,我发现自己缺少“默认不可变”方法提供的简单性和自由度。

Is it good practice to make all immutable variables final ?将所有不可变变量设为final是好习惯吗?

I recommend the following practices, which have served me well as a professional developer over the past decade:我推荐以下实践,这些实践在过去十年中对我作为一名专业开发人员很有帮助:

  • Class members should be declare final by default.默认情况下,类成员应声明为final Members should be declared non-final only where we explicitly want to make them mutable.只有在我们明确想让它们可变的情况下,才应该将成员声明为非最终的。
  • Variables within methods should be declared final where the value provided (in terms of simlicity and correctness guarantees) outweighs any concerns like clutter.方法中的变量应该被声明为 final,其中提供的值(在简单性和正确性保证方面)超过任何诸如混乱之类的问题。 For short methods with few variables, the benefit is mininal.对于变量很少的简短方法,好处是微乎其微的。 For long methods with many variables, the benefit will be greater.对于有很多变量的长方法,好处会更大。

The use of final method variables also prevents certain coding patterns that are difficult to reason about, due to complex use of mutable state.由于可变状态的复杂使用,最终方法变量的使用还可以防止某些难以推理的编码模式。 Mutable state is sometimes necessary, but often isn't.可变状态有时是必要的,但通常不是。

As an excercise, try declaring all method variable final by default for a day, to get a feel for the patterns and practices needed to support this approach.作为练习,尝试在一天内默认将所有方法变量声明为 final,以了解支持这种方法所需的模式和实践。

There is no universal best practice here.这里没有通用的最佳实践。 There are tradeoffs to be made between the above benefits and conciseness (some feel that final keywords add clutter, though I don't tend to agree).在上述好处和简洁性之间需要进行权衡(有些人认为final关键字会增加混乱,但我并不倾向于同意)。 The use of final may also depend on compatability with other coding practices (eg some people like to use default constructors, and then use setters to populate fields, which I'd argue is not a good practice). final 的使用也可能取决于与其他编码实践的兼容性(例如,有些人喜欢使用默认构造函数,然后使用 setter 来填充字段,我认为这不是一个好的做法)。

There are many proponents of the "always final , unless there's a reason not to" approach.许多“总是final ,除非有理由不这样做”方法的支持者 There are also many who advocate for using final more sparingly, including Bob Martin in Clean Code .也有许多人主张更谨慎地使用 final,包括Clean Code 中的Bob Martin。 The Google Java Style Guide is notably silent on this question. Google Java Style Guide对这个问题特别沉默。

I don't agree that liberal use of final goes against the principles of clean code, which values simplicity and self-documenting code.我不同意对final自由使用违背干净代码的原则,它重视简单性和自我记录代码。

Do you use final modifier for all your immutable variables in your programs?您是否对程序中的所有不可变变量使用final修饰符?

As discussed above, generally:如上所述,一般来说:

  • Class members - yes, final unless there is a reason not to, for a given class member.班级成员 - 是的,对于给定的班级成员,除非有理由不这样做,否则是final
  • Method variables - not always, but often for non-trivial methods.方法变量 - 并非总是如此,但通常用于非平凡的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM