Java 什么时候应该对方法参数和局部变量使用final?

Java 什么时候应该对方法参数和局部变量使用final?,java,final,Java,Final,我发现一些参考()建议尽可能多地使用final,我想知道这有多重要。这主要是在方法参数和局部变量的上下文中,而不是在最终的方法或类中。对于常量,这显然是有意义的 一方面,编译器可以进行一些优化,使程序员的意图更加清晰。另一方面,它增加了冗长,并且优化可能很琐碎 这是我应该努力记住的事情吗 这是我应该努力记住去做的事情吗 不,如果您使用的是Eclipse,因为您可以配置保存操作来自动添加这些最终修改器。然后你就可以通过更少的努力获得好处。好吧,这一切都取决于你的风格。。。如果你想在不修改变量时看到

我发现一些参考()建议尽可能多地使用
final
,我想知道这有多重要。这主要是在方法参数和局部变量的上下文中,而不是在最终的方法或类中。对于常量,这显然是有意义的

一方面,编译器可以进行一些优化,使程序员的意图更加清晰。另一方面,它增加了冗长,并且优化可能很琐碎

这是我应该努力记住的事情吗

这是我应该努力记住去做的事情吗


不,如果您使用的是Eclipse,因为您可以配置保存操作来自动添加这些最终修改器。然后你就可以通过更少的努力获得好处。

好吧,这一切都取决于你的风格。。。如果你想在不修改变量时看到最终结果,那么就使用它。如果你不喜欢看。。。那就别提了

我个人喜欢尽可能少的罗嗦,所以我倾向于避免使用不必要的额外关键字

不过我更喜欢动态语言,所以我喜欢避免冗长也就不足为奇了

所以,我想说的是,选择你倾向的方向,跟着它走(不管是什么情况,试着保持一致)



顺便说一句,我曾经在使用和不使用这种模式的项目上工作过,我没有看到在bug或错误的数量上有什么不同。。。我不认为这是一种模式可以极大地提高你的bug数量或任何东西,但这也是一种风格,如果你喜欢表达你不想修改它的意图,那么就继续使用它。

正如你所说,这是一种折衷,但我更喜欢显式使用而不是隐式使用。这将有助于为未来的代码维护者消除一些模棱两可的地方——即使只是您

如果您有内部(匿名)类,并且该方法需要访问包含该方法的变量,则需要将该变量作为final


除此之外,您所说的是对的。

最终版的开发时好处至少与运行时好处一样重要。它告诉未来的代码编辑器一些关于您意图的信息

将类标记为“final”表示您在设计或实现该类的过程中没有努力优雅地处理扩展。如果读者可以对类进行更改,并且希望删除“final”修饰符,那么他们可以自行承担风险。由他们来确保类能够很好地处理扩展

将变量标记为“final”(并在构造函数中赋值)对于依赖项注入非常有用。它表示变量的“协作者”性质

将方法标记为“final”在抽象类中很有用。它清楚地描绘了延伸点的位置

痴迷于:

  • 最终字段-将字段标记为最终字段将强制在构造结束时对其进行设置,使该字段引用不可变。这允许安全地发布字段,并且可以避免以后读取时需要同步。(请注意,对于对象引用,只有字段引用是不可变的-对象引用引用的内容仍然可以更改,并且会影响不可变性。)
  • 最终静态字段-尽管我现在在许多情况下使用枚举,我以前使用静态最终字段
考虑但明智地使用:

    最终类——框架/API设计是我唯一考虑的情况。
  • 最终方法-基本上与最终类相同。如果您疯狂地使用模板方法模式并将内容标记为final,那么您可能过于依赖继承,而对委托的依赖不够
忽略,除非感觉肛门:

  • 方法参数和局部变量-我很少这样做,主要是因为我很懒,而且我发现这会使代码混乱。我完全承认,标记我不打算修改的参数和局部变量是“正确的”。我希望这是默认的。但事实并非如此,我发现随着期末考试的结束,代码更难理解。如果我在其他人的代码中,我不会将它们取出,但如果我在编写新代码,我不会将它们放入。一个例外是,您必须将某个内容标记为final,以便可以从匿名内部类中访问它

  • 编辑:请注意,如所述,最终局部变量实际上非常有用的一个用例是,将值分配给
    if
    /
    else
    分支中的var


如果您正在编写一个应用程序,比如说,一年后有人必须阅读代码,那么可以使用final on变量,该变量不应一直修改。通过这样做,您的代码将更加“自文档化”,并且您还减少了其他开发人员执行愚蠢操作的机会,例如使用局部常量作为局部临时变量


如果您正在编写一些一次性代码,那么,不,不要费心识别所有常量并将它们设为final。

我将尽可能多地使用final。如果无意中更改了字段,则这样做将标记。我还将方法参数设置为final。这样做的时候,我从他们试图“设置”一个忘记Java传递值的参数时我接管的代码中发现了几个bug。

这个问题不清楚这是否明显,但使一个方法参数成为final只会影响方法的主体。它不会向调用者传达任何有关方法意图的有趣信息。传入的对象仍然可以在方法中进行变异(final不是常量),并且变量的范围在方法中

为了回答您的精确问题,我不会费心让一个实例或局部变量(包括方法参数)成为final,除非代码需要它(例如变量是re)
 public int processSomethingCritical( final int x, final int y ){
 // hundreds of lines here 
     // for loop here...
         int x2 = 0;
        x++; // bug aarrgg...
 // hundreds of lines there
 // if( x == 0 ) { ...

 }
 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }
public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}
public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}
public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}
 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }
Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler
public final class SomeClass {
  //  . . . Class contents
}
public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }
public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}
final int CM_PER_INCH = 2.54;
final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"
local variable is accessed from inner class, must be declared final
final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);
Hello World!
A String
    final String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
        default:
            throw new IllegalStateException();
    }
    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            //break; whoops forgot break.. 
            //this will cause a compile error for final ;P @Recurse
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";
    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        //should have handled all the cases for pluginType
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";
type plugin = CandidateExport | JobPostingImport

let p = CandidateExport

let name = match p with
    | CandidateExport -> "Candidate Stuff"
    | JobPostingImport -> "Blah" ;;
(define name 
    (match b
      ['CandidateExport "Candidate Stuff"]
      ['JobPostingImport "Blah"]))