繁体   English   中英

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

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

在我读过的一本 Java 书中, “一般来说,如果不需要重新分配变量,则始终将变量声明为 final,将常量字段声明为 static final 是个好主意” 我开始遵循这个建议。 但是当我开始编码时,我发现几乎所有的变量都是不可变的。 但是使用关键字«final»会使行变得更长,因此更难阅读代码,这违背了干净代码的原则。 所以这里是我的问题:

  1. 将所有不可变变量设为“final”是一个好习惯吗?
  2. 您是否对程序中的所有不可变变量使用 «final» 修饰符?
  3. 如果没有,你什么时候使用«final»,什么时候跳过使用这个关键字?

这是我的代码教练存储库中的程序示例。 所有变量都是最终的。 同样的情况几乎出现在存储库中的所有其他程序中。

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);
    }
}

您可能想要声明变量final原因有多种,包括:

  • 简单性- 必须初始化最终变量,并且不能重新分配。 因此,一段代码使读者不必对可变状态或未初始化的变量进行推理。 编译器将阻止两者。 这意味着 final 变量还将防止错误,例如意外重新分配或意外使用未初始化的类成员。

  • 自记录- 声明为 final 的变量或类成员是向用户明确表示永远不应重新分配变量的意图的信号。

  • 线程安全- 无需同步即可安全读取最终引用。 一个不可变对象(即所有成员字段都是最终的,并且可以是原始对象或对其他不可变对象的引用),可以在没有同步的情况下并发访问。

  • 编译器所需的用例- 只有有效的最终变量才能在 try-with-resources 表达式中引用,或由 lambdas 捕获。 有关 beeween final有效 final隐式 final变量之间差异的概述,请参阅以下此答案

顺便说一句,我注意到有使用“纯函数”语言(例如 F# 和 Haskell)经验的开发人员倾向于自由使用final 在这些语言中,所有值都是“默认不可变的”。 在使用这些语言后回到 Java 时,我发现自己缺少“默认不可变”方法提供的简单性和自由度。

将所有不可变变量设为final是好习惯吗?

我推荐以下实践,这些实践在过去十年中对我作为一名专业开发人员很有帮助:

  • 默认情况下,类成员应声明为final 只有在我们明确想让它们可变的情况下,才应该将成员声明为非最终的。
  • 方法中的变量应该被声明为 final,其中提供的值(在简单性和正确性保证方面)超过任何诸如混乱之类的问题。 对于变量很少的简短方法,好处是微乎其微的。 对于有很多变量的长方法,好处会更大。

由于可变状态的复杂使用,最终方法变量的使用还可以防止某些难以推理的编码模式。 可变状态有时是必要的,但通常不是。

作为练习,尝试在一天内默认将所有方法变量声明为 final,以了解支持这种方法所需的模式和实践。

这里没有通用的最佳实践。 在上述好处和简洁性之间需要进行权衡(有些人认为final关键字会增加混乱,但我并不倾向于同意)。 final 的使用也可能取决于与其他编码实践的兼容性(例如,有些人喜欢使用默认构造函数,然后使用 setter 来填充字段,我认为这不是一个好的做法)。

许多“总是final ,除非有理由不这样做”方法的支持者 也有许多人主张更谨慎地使用 final,包括Clean Code 中的Bob Martin。 Google Java Style Guide对这个问题特别沉默。

我不同意对final自由使用违背干净代码的原则,它重视简单性和自我记录代码。

您是否对程序中的所有不可变变量使用final修饰符?

如上所述,一般来说:

  • 班级成员 - 是的,对于给定的班级成员,除非有理由不这样做,否则是final
  • 方法变量 - 并非总是如此,但通常用于非平凡的方法。

暂无
暂无

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

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