在Java中,有一种做法是声明每个变量(本地或类),如果确实是参数final。
虽然这使得代码更加冗长,但这有助于轻松阅读/掌握代码,并且还可以防止错误,因为意图已明确标记。
您对此有何看法,您对此有何看法?
我认为这一切都与良好的编码风格有关。当然,你可以编写好的,强大的程序而不需要在任何地方使用大量的final
修饰符,但是当你想到它时......
将final
添加到所有不应该改变的事情上只会缩小您(或下一个程序员,处理您的代码)会误解或误用导致您的代码的思维过程的可能性。当他们现在想要改变你以前不可改变的东西时,至少应该响起一些钟声。
首先,在你的代码中看到很多final
关键字看起来很尴尬,但很快你就会停止注意到这个词本身,并且只会认为,这个东西永远不会从这一点改变 - (你可以从我这里拿走;-)
我认为这是一个很好的做法。我并不是一直都在使用它,但是当我能够并且标记一些final
它是有意义的时候我会这样做。
我必须为我的工作阅读很多代码。在实例变量上缺少最终结果是让我烦恼的最重要的事情之一,并使得理解代码变得不必要。对于我的钱,最终的局部变量导致比清晰度更混乱。该语言应该被设计为默认,但我们必须忍受错误。有时它特别适用于循环和if-else树的明确赋值,但大多数情况下它往往表明你的方法太复杂了。
听起来反对使用final关键字的最大理由之一是“它不必要”,而且“浪费空间”。
如果我们承认这里许多伟大帖子所指出的“最终”的许多好处,虽然承认它需要更多的打字和空间,我认为Java应该默认变量“最终”,并要求标记“可变的“如果编码员希望它是。
显然,final应该用于常量,并强制实现不变性,但是方法还有另一个重要用途。
有效的Java有一个完整的项目(项目15)指出了非预期继承的缺陷。实际上,如果您没有为继承设计和记录您的类,继承它可能会产生意想不到的问题(该项提供了一个很好的示例)。因此,建议您对任何不打算从中继承的类和/或方法使用final。
这可能看起来很严苛,但这是有道理的。如果您正在编写一个供其他人使用的类库,那么您不希望它们继承自那些不是为它设计的东西 - 您将自己锁定到该类的特定实现中以实现后向兼容性。如果你是在一个团队中编码,没有什么可以阻止团队中的另一个成员去除最终的,如果他们真的必须。但关键字使他们思考他们正在做什么,并警告他们他们继承的类不是为它设计的,所以他们应该格外小心。
另一个警告是,许多人混淆final意味着实例变量的内容不能改变,而不是引用不能改变。
即使对于局部变量,知道它被声明为final也意味着我不必担心稍后会更改引用。这意味着在调试时我会在稍后看到该变量,我相信它指的是同一个对象。在寻找错误时,我不必担心这一点。一个好处是,如果99%的变量被宣布为最终变量,那么真正变量的少数变量会更好。此外,最终让编译器找到一些可能会被忽视的愚蠢错误。
选择为每个方法中的每个参数键入final
将对编码员和代码阅读器产生如此大的刺激。
一旦激怒超出合理的切换到Scala,默认情况下参数是最终的。
或者,您始终可以使用自动为您执行此操作的代码样式工具。所有IDE都实现了它们或作为插件。
与Java中的变量一起使用时的最终结果在C ++中提供了常量的替代。因此,当final和static用于变量时,它变得不可变。同时使迁移的C ++程序员非常高兴;-)
当与引用变量一起使用时,它不允许您重新引用该对象,尽管可以操作该对象。
当final与方法一起使用时,它不允许子类覆盖该方法。
一旦使用非常清楚,应小心使用。它主要取决于设计,因为使用final方法不会有助于多态性。
只有当你确定变量的值将/永远不会改变时,才应该将它用于变量。还要确保遵循SUN鼓励的编码约定。例如:final int COLOR_RED = 1; (大写由下划线分隔)
使用引用变量时,仅在需要对特定对象的不可变引用时才使用它。
关于可读性部分,随后在使用final修饰符时注释起着非常重要的作用。
我从不在局部变量上使用它们,添加的详细程度没有什么意义。即使您不认为该变量应该被重新分配,这对于下一个改变该代码的人来说也没有什么区别,并且由于代码正在被更改,因此使其成为最终的任何原始目的可能不再有效。如果只是为了清晰起见,我认为由于冗长的负面影响而失败。
几乎同样适用于成员变量,因为它们提供的好处很少,除了常量的情况。
它也不影响不变性,因为不可变的东西的最佳指标是它被记录为这样和/或没有可以改变对象的方法(这一点,同时使类最终是保证这一点的唯一方法)它是不可改变的)。
但是,嘿,这只是我的意见:-)
我设置Eclipse以在所有未修改的字段和属性上添加final。这可以很好地使用Eclipse“保存动作”,它在保存文件时添加这些最终修饰符(以及其他内容)。
强烈推荐。
查看Eclipse Save Actions的my blog post。
我几乎不使用final方法或类,因为我喜欢让人们覆盖它们。
否则,如果它是public/private static final type SOME_CONSTANT;
我最后只使用
痴迷于:
考虑但明智地使用:
忽略除非感觉肛门:
对于论据,我认为他们不需要。 Mostley他们只是伤害了可读性。重新分配参数变量是非常愚蠢的,我应该非常确信它们无论如何都可以被视为常量。
Eclipse最终变成红色这一事实使得更容易在代码中发现变量声明,我认为这些声明在大多数情况下会提高读取性。
我试图强制执行任何和所有变量都应该是最终的规则,因为没有极端的有效理由。回答“这个变量是什么?”要容易得多。问题,如果你只需要找到启动并确信这就是它。
实际上,我现在对非最终变量感到相当紧张。这就像把刀挂在头顶上的一根线上,或者只是把它放在你的厨房抽屉之间的区别......
最终变量只是标记值的好方法。
非final变量绑定到一些容易出错的算法的一部分。
一个很好的特性是,当大多数时候选择在算法中使用变量时,解决方法是编写一个方法,这通常可以显着改善代码。
我已经编写了一段时间并且尽可能地使用final。在做了一段时间后(对于变量,方法参数和类属性),我可以说90%(或更多)我的变量实际上是最终的。我认为当你不想修改变量时没有修改变量的好处(我之前看过,有时候很痛苦)会为代码中额外的输入和额外的“最终”关键字付出代价。
话虽如此,如果我要设计一种语言,我会将每个变量设为final,除非被其他关键字修改。
想到,我不会在课程和方法上使用最终版本。这是一个或多或少复杂的设计选择,除非您的类是实用程序类(在这种情况下,您应该只有一个私有构造函数)。
我还使用Collections.unmodifiable ...在需要时创建不可修改的列表。
对事件侦听器使用匿名本地类等是Java中的常见模式。 final关键字的最常见用法是确保even监听器可以访问范围中的变量。
但是,如果您发现自己被要求在代码中添加大量最终语句。这可能是一个很好的暗示,你做错了什么。
上面发布的文章给出了这个例子:
public void doSomething(int i, int j) {
final int n = i + j; // must be declared final
Comparator comp = new Comparator() {
public int compare(Object left, Object right) {
return n; // return copy of a local variable
}
};
}
我将它用于内部和外部方法的常量。
我有时只将它用于方法,因为我不知道子类是否不想覆盖给定的方法(无论出于何种原因)。
至于类,仅针对某些基础结构类,我使用过final类。
如果在函数内部写入函数参数,IntelliJ IDEA会发出警告。所以,我已经停止使用final作为函数参数。我也没有在java Runtime库中看到它们。
标记类final也可以使一些方法绑定在编译时而不是运行时发生。考虑下面的“v2.foo()” - 编译器知道B不能有子类,因此不能覆盖foo(),因此在编译时需要调用实现。如果B类未标记为final,那么v2的实际类型可能是某个扩展B并覆盖foo()的类。
class A {
void foo() {
//do something
}
}
final class B extends A {
void foo() {
}
}
class Test {
public void t(A v1, B v2) {
v1.foo();
v2.foo();
}
}
强烈建议使用final作为常量。但是,我不会将它用于方法或类(或至少考虑它一段时间),因为它使测试更难,如果不是不可能的话。如果你绝对必须让一个类或方法最终,请确保这个类实现了一些接口,所以你可以让一个mock实现相同的接口。
在使用之前,您确实需要了解final关键字的完整用法。它可以应用于变量,字段,方法和类,并对其有不同的影响
我建议查看下面链接的文章了解更多详情。
final
修饰符,尤其是变量,是一种让编译器强制执行通常合理的约定的方法:确保(本地或实例)变量只分配一次(不多也不少)。通过确保变量在使用之前明确赋值,您可以避免使用NullPointerException
的常见情况:
final FileInputStream in;
if(test)
in = new FileInputStream("foo.txt");
else
System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned
通过防止变量被多次分配,您可以阻止过于宽泛的范围。而不是这个:
String msg = null;
for(int i = 0; i < 10; i++) {
msg = "We are at position " + i;
System.out.println(msg);
}
msg = null;
我们鼓励您使用此:
for(int i = 0; i < 10; i++) {
final String msg = "We are at position " + i;
System.out.println(msg);
}
一些链接:
我非常教条宣称每个可能的变量final
。这包括方法参数,局部变量和很少的值对象字段。我有三个主要原因可以在任何地方声明最终变量:
但是,我确实认为最终的类和方法几乎没有最终变量引用那么有用。与这些声明一起使用时,final
关键字只是为自动化测试和以前所未有的方式使用代码提供了障碍。
Effective Java有一个项目“赞成不可变对象”。将字段声明为final可以帮助您对此采取一些小步骤,但对于真正不可变的对象,当然还有更多。
如果您知道对象是不可变的,则可以共享它们以便在没有同步担忧的情况下在许多线程/客户端之间进行读取,并且更容易推断出程序的运行方式。
我从来没有遇到过变量上的最终关键字阻止我犯错误的情况,所以目前我认为这是浪费时间。
除非有这样做的真正原因(因为你想要对该变量做出最终的具体观点),我宁愿不这样做,因为我发现它使代码的可读性降低。
但是,如果你没有发现它会使代码更难以阅读或更长时间地写入,那么一定要去寻找它。
编辑:作为一个澄清(并尝试赢回选票),我不是说不要将常数标记为最终,我说不要做的事情如下:
public String doSomething() {
final String first = someReallyComplicatedExpressionToGetTheString();
final String second = anotherReallyComplicatedExpressionToGetAnother();
return first+second;
}
它只是使代码(在我看来)更难阅读。
值得记住的是,所有最终的做法都是阻止你重新分配一个变量,它不会让它变成不可变的或类似的东西。
Final应始终用于常量。当定义变量的规则很复杂时,它对于短期变量(在单个方法中)甚至有用。
例如:
final int foo;
if (a)
foo = 1;
else if (b)
foo = 2;
else if (c)
foo = 3;
if (d) // Compile error: forgot the 'else'
foo = 4;
else
foo = -1;
我一直使用final
作为对象属性。
当在对象属性上使用时,final
关键字具有可见性语义。基本上,在构造函数返回之前设置最终对象属性的值。这意味着只要你不让this
引用转义构造函数并且你使用final
来表示你的所有属性,你的对象(在Java 5语义下)是保证正确构造的,并且因为它也是不可变的,它可以是安全地发布到其他线程。
不可变对象不仅仅是线程安全。它们还可以更容易地推断出程序中的状态转换,因为可以改变的空间是故意的,并且如果一致地使用,则仅限于应该改变的事物。
我有时也会把方法做成最终,但不是经常。我很少把课程定稿。我一般这样做是因为我没有必要这样做。我通常不会使用很多继承。我更喜欢使用接口和对象组合 - 这也适用于我发现通常更容易测试的设计。当您对接口而不是具体类进行编码时,在使用jMock等框架进行测试时,不需要使用继承,使用接口创建模拟对象比使用具体类更容易。
我想我应该让我的大部分班级最终完成,但我还没有进入habbit。