将 java 方法参数设为 final

Posted

技术标签:

【中文标题】将 java 方法参数设为 final【英文标题】:Making java method arguments as final 【发布时间】:2011-05-08 22:21:56 【问题描述】:

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 ....

【问题讨论】:

有些代码分析器会在参数被重用或重新分配时发出警告。 (局部变量相同)恕我直言,如果您发现不希望更改这些参数,这是捕获此类参数的更好方法。 Why should I use the keyword "final" on a method parameter in Java?的可能重复 我觉得Java应该将所有输入法参数默认设置为final。然后,如果我想修改参考,我将不得不手动进行。这样一来,内疚因素就可以防止许多此类案件发生。 【参考方案1】:

由于形式方法参数是一个局部变量,因此只有将它们声明为 final 时,才能从内部匿名类访问它们。

这使您不必在方法主体中声明另一个局部最终变量:

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

【讨论】:

+1:这是一个重要的用例,也是您需要的唯一时候。 (其余的时间只是方便帮助程序员的问题。) 请问这背后的原因是什么? Java 8 不再需要。 @simgineer 在这里阅读:***.com/questions/28408109/… @AmitParashar 没错,但 Java 8 只是让您不必在每次必须在内部类中使用变量时都使用关键字“final”...现实情况是,编译器只是使 finality 隐含,您仍然需要将变量 effectively final... 所以,您仍然会遇到编译时错误,以防万一您稍后尝试分配给它! Java 8潜行 100 :)【参考方案2】:

从The final word on the final keyword提取

最终参数

以下示例声明了最终参数:

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 不会意外地 方法复位。这是一个方便的方法 防止一个阴险的错误 错误地改变了 你的参数。通常来说,一般来说, 短方法是更好的方法 防止此类错误,但 最终参数可能很有用 除了你的编码风格。

请注意,最终参数不是 被认为是方法的一部分 签名,并被忽略 解析方法调用时的编译器。 参数可以声明为最终的(或 不)对如何的没有影响 方法被覆盖。

【讨论】:

在这个例子中使用对象而不是原语可能会更好,因为原语的变化总是只在方法内部可见。对于对象,您仍然可以更改它们。你只是不能指向一个新的对象。事实上,现在我想起来了,final 与省略它相比并没有真正改变任何东西,除了使用 AIC 保存变量声明并让编译器指出您出于某种原因不想修改的参数的意外修改.【参考方案3】:

final 阻止您为变量分配新值,这有助于发现拼写错误。从风格上讲,您可能希望保持接收到的参数不变并仅分配给局部变量,因此 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;

【讨论】:

将参数声明为 final 很有用的好例子。我偏爱这一点,但它们也是 3+ 参数的满口。【参考方案4】:

这并没有太大的不同。这只是意味着你不能写:

stamp = null;
fTz = new ...;

但你仍然可以写:

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

这主要是对跟随您的维护程序员的一个提示,即您不会在方法中间的某个地方为参数分配新值,因为它不明显,因此可能会引起混淆。

【讨论】:

【参考方案5】:

在 Java 中用于参数/变量时的 final 关键字将引用标记为 final。在将对象传递给另一个方法的情况下,系统会创建引用变量的副本并将其传递给该方法。通过将新参考标记为最终,您可以保护它们免于重新分配。它有时被认为是一种很好的编码习惯。

【讨论】:

我必须补充一点:如果参数是原始的,我看不出有任何区别。此外,如果参数是集合(对象列表...),添加 final 并不能阻止它们被修改。 不变性始终是一个理想的特征。 Java 没有开箱即用。将变量设为 final 至少可以确保引用的完整性。 我同意。但如果我们真的想实现对象的不变性,我们可以尝试进行深度克隆。 final 对不变性毫无帮助。无论参数是否标记为最终值,对原始值的更改都会在方法范围之外丢失。无论参数是否标记为最终,对可变对象的更改都会传播到范围之外。 “没用”是我想到的词。 不可变引用是迈向不变性的第一步。【参考方案6】:

对于此方法的主体,final 关键字将防止参数引用被意外重新分配,从而在这些情况下产生编译错误(大多数 IDE 会立即抱怨)。有些人可能会争辩说,尽可能使用final 通常会加快速度,但在最近的 JVM 中并非如此。

【讨论】:

【参考方案7】:

列出了我看到的两个优点:

1 将方法参数标记为 final 可防止在方法内重新分配参数

你的例子

    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 ..
    
    

在复杂的方法中,将参数标记为 final 将有助于将这些参数意外解释为方法局部变量,并且重新分配为编译器将标记这些情况,如示例中所示。

2 将参数传递给匿名内部类

由于形式方法参数是一个局部变量,因此只有在声明为 final 的情况下,您才能从内部匿名类访问它们。

【讨论】:

【参考方案8】:

它只是 Java 中的一个构造,可帮助您定义合同并遵守合同。这里有类似的讨论:http://c2.com/cgi/wiki?JavaFinalConsideredEvil

顺便说一句 -(正如 twiki 所说),如果您遵循良好的编程原则并重新分配/重新定义传入的参数引用,则将 args 标记为 final 通常是多余的。

在最坏的情况下,如果你重新定义了 args 引用,它不会影响传递给函数的实际值 - 因为只传递了一个引用。

【讨论】:

【参考方案9】:

我说的是一般将变量和字段标记为 final - 不仅适用于方法参数。 (将方法/类标记为 final 是完全不同的事情)。

这对您的代码的读者/未来维护者来说是一个好处。与变量的合理名称一起,它有助于您的代码读者看到/理解所讨论的变量代表什么 - 并且让读者放心,只要您在同一范围内看到变量,含义就会保持不变一样,所以(s)他不必总是摸不着头脑来弄清楚变量在每种情况下的含义。我们已经看到太多滥用“重用”变量的行为,这使得即使是简短的代码 sn-p 也难以理解。

【讨论】:

【参考方案10】:

- 过去(在 Java 8 之前 :-))

显式使用“final”关键字会影响内部匿名类的方法变量的可访问性。

- 在现代(Java 8+)语言中,不需要这样的用法:

Java 引入了“有效的最终”变量。如果代码不暗示变量值的更改,则局部变量和方法参数被假定为最终值。因此,如果您在 Java8+ 中看到这样的关键字,您可以认为它是不必要的。 “有效最终”的引入使我们在使用 lambdas 时键入的代码更少。

【讨论】:

【参考方案11】:

final 关键字阻止您为参数分配新值。我想用一个简单的例子来解释一下

假设我们有一个方法

方法1()

日期 dateOfBirth =new Date("1/1/2009");

method2(dateOfBirth);

method3(dateOfBirth);

public mehod2(Date dateOfBirth) .... .... ....

public mehod2(Date dateOfBirth) .... .... ....

在上述情况下,如果在方法 2 中为“dateOfBirth”分配了新值,那么这将导致方法 3 的输出错误。因为传递给method3的值不是传递给method2之前的值。所以为了避免这个final关键字被用于参数。

这也是 Java 编码最佳实践之一。

【讨论】:

这不太对。即使参数 dateOfBirth 在 method2() 中更改为另一个值,这对 method2() 也没有影响,因为 Java 通过值而不是引用传递。

以上是关于将 java 方法参数设为 final的主要内容,如果未能解决你的问题,请参考以下文章

java方法的参数 为啥有时会加上final关键字

Java编程思想 -- 泛型概括总结

java 里定义的方法参数 (final String... args)

java中final用在参数中表示啥?

java 里定义的方法参数啥意思(final String... args)

Java中final修饰参数的作用