我发现了一些建议尽可能多地使用的参考资料(例如),我想知道这有多重要。final这主要是在方法参数和局部变量的上下文中,而不是最终方法或类。对于常量,这显然是有道理的。
final
一方面,编译器可以做一些优化,让程序员的意图更加清晰。另一方面,它增加了冗长,优化可能是微不足道的。
这是我应该努力记住的事情吗?
沉迷于:
考虑但明智地使用:
除非感觉肛门,否则忽略:
方法参数和局部变量——我很少这样做,主要是因为我很懒,而且我发现它会使代码混乱。我完全承认我不会修改的标记参数和局部变量是“更正确的”。我希望它是默认值。但事实并非如此,而且我发现随着决赛的结束,代码更难理解。如果我在别人的代码中,我不会把它们拉出来,但如果我正在编写新代码,我不会把它们放进去。一个例外是你必须标记一些最终的东西以便你可以访问它来自匿名内部类。
编辑:请注意, @adam-gent提到的最终局部变量实际上非常有用的一个用例是当值被分配给if/else分支中的 var 时。
if
else
if,else,switch
因此,在使用条件时,您应该尝试始终(恕我直言)使用最终变量。
让我给你举个例子:
final String name; switch(pluginType) { case CANDIDATE_EXPORT: name = "Candidate Stuff"; break; case JOB_POSTING_IMPORT: name = "Blah"; break; default: throw new IllegalStateException(); }
现在如果添加另一个case语句并且不设置name编译器将失败。如果您没有在每种情况下都中断(您设置变量),编译器也会失败。这使您可以使 Java 与 Lisp 的表达式非常相似let,并使您的代码不会大量缩进(因为词法范围变量)。
case
name
let
正如@Recurse 指出的那样(但显然是-1 me),您可以执行上述操作而无需String name final获取编译器错误(我从未说过您不能),但是您可以轻松地使编译器错误在切换后消失设置名称语句丢弃了表达式语义或更糟的是忘记了break如果不使用就不能导致错误(尽管@Recurse 说)final:
String name
break
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";
由于错误设置名称(除了忘记break另一个错误之外)我现在可以不小心这样做:
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";
final 变量强制对应该是什么名称进行单一评估。类似于具有返回值的函数必须始终返回一个值(忽略异常),名称切换块将必须解析名称并因此绑定到该切换块,这使得重构代码块更容易(即 Ecipe 重构:提取方法) .
OCaml 中的上述内容:
type plugin = CandidateExport | JobPostingImport let p = CandidateExport let name = match p with | CandidateExport -> "Candidate Stuff" | JobPostingImport -> "Blah" ;;
match ... with ...评估像一个函数,即表达式。注意它看起来像我们的 switch 语句。
match ... with ...
这是 Scheme (Racket or Chicken) 中的一个示例:
(define name (match b ['CandidateExport "Candidate Stuff"] ['JobPostingImport "Blah"]))