为什么我应该在Java的方法参数中使用关键字“final”?

当我在方法参数上使用final关键字时,我无法理解final关键字的真正用处。

如果我们排除匿名类的使用,可读性和意图声明,那么对我来说似乎几乎没有价值。

强化一些数据保持不变并不像看起来那么强劲。

  • 如果参数是一个基元,那么它将不起作用,因为该参数作为一个值传递给该方法,并且改变它在该范围之外将不起作用。

  • 如果我们通过引用传递一个参数,那么引用本身就是一个局部变量,并且如果引用从方法内部改变了,那么这个方法范围之外就没有任何影响。

  • 考虑下面的简单测试示例。 尽管该方法改变了给定的参考值,但该测试通过,但它没有效果。

    public void testNullify() {
        Collection<Integer> c  = new ArrayList<Integer>();      
        nullify(c);
        assertNotNull(c);       
        final Collection<Integer> c1 = c;
        assertTrue(c1.equals(c));
        change(c);
        assertTrue(c1.equals(c));
    }
    
    private void change(Collection<Integer> c) {
        c = new ArrayList<Integer>();
    }
    
    public void nullify(Collection<?> t) {
        t = null;
    }
    

    有时为了变得清晰(为了可读性),变量不会改变。 这里有一个简单的例子,使用final可以节省一些可能的麻烦

    public void setTest(String test) {
        test = test;
    }
    

    如果您忘记了setter上的'this'关键字,那么您要设置的变量不会被设置。 但是,如果你在参数上使用了final关键字,那么bug在编译时就会被捕获。


    停止变量的重新分配

    尽管这些答案在智力上很有趣,但我还没有阅读简单的答案:

    如果希望编译器防止将变量重新分配给其他对象,请使用关键字final。

    无论变量是静态变量,成员变量,局部变量还是变量/参数变量,效果都完全相同。

    让我们看看实际效果。

    考虑这个简单的方法,其中两个变量(arg和x)都可以重新分配不同的对象。

    // Example use of this method: 
    //   this.doSomething( "tiger" );
    void doSomething( String arg ) {
      String x = arg;   // Both variables now point to the same String object.
      x = "elephant";   // This variable now points to a different String object.
      arg = "giraffe";  // Ditto. Now neither variable points to the original passed String.
    }
    

    将局部变量标记为final。 这会导致编译器错误。

    void doSomething( String arg ) {
      final String x = arg;  // Mark variable as 'final'.
      x = "elephant";  // Compiler error: The final local variable x cannot be assigned. 
      arg = "giraffe";  
    }
    

    相反,让我们将参数变量标记为final。 这也会导致编译器错误。

    void doSomething( final String arg ) {  // Mark argument as 'final'.
      String x = arg;   
      x = "elephant"; 
      arg = "giraffe";  // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
    }
    

    故事的道德启示:

    如果你想确保一个变量总是指向同一个对象,那么标记变量final。

    永不重新分配参数

    作为良好的编程习惯(以任何语言),您绝不应该将参数/变量变量重新分配给除调用方法传递的对象之外的其他对象。 在上面的例子中,不应该写行arg = 。 由于人类犯错误,而程序员是人类,让我们让编译器来帮助我们。 将每个参数/参数变量标记为'final',以便编译器可以查找并标记任何此类重新分配。

    回想起来

    正如其他答案中所指出的那样......鉴于Java的原始设计目标是帮助程序员避免愚蠢的错误,例如读取数组尾部,Java应该被设计为自动将所有参数/参数变量强制为'final'。 换句话说,参数不应该是变量。 但后见之明是20/20的愿景,而Java设计师当时充满了自己的双手。

    为了完整性增加了另一个案例

    public class MyClass {
        private int x;
        //getters and setters
    }
    
    void doSomething( final MyClass arg ) {  // Mark argument as 'final'.
    
       arg =  new MyClass();  // Compiler error: The passed argument variable arg  cannot be re-assigned to another object.
    
       arg.setX(20); // allowed
      // We can re-assign properties of argument which is marked as final
     }
    

    是的,除了匿名课程,可读性和意向声明几乎毫无价值。 这三件事情没有价值吗?

    就我个人而言,我倾向于不使用final作为局部变量和参数,除非我在匿名内部类中使用该变量,但我当然可以看到那些想清楚表明参数值本身不会改变的人的观点即使它引用的对象改变其内容)。 对于那些发现增加可读性的人,我认为这是一个完全合理的做法。

    如果有人真的声称它确实保持了数据的不变 - 但我不记得看到任何这样的说法,你的观点会更加重要。 你是否暗示有一大批开发者表示final比实际效果更强?

    编辑:我应该真的用Monty Python的参考来总结这一切; 这个问题似乎有点类似于问“罗马人为我们做了什么?”

    链接地址: http://www.djcxy.com/p/3539.html

    上一篇: Why should I use the keyword "final" on a method parameter in Java?

    下一篇: Passing values in Python