将成员变量声明为只读有什么好处?它只是防止在类的生命周期中更改某些人,或者是否由于此关键字而导致编译器速度提高
什么是空指针异常(java.lang.NullPointerException)以及它们的原因是什么?
可以使用哪些方法/工具来确定原因,以便停止异常导致程序过早终止?
我发现了一些建议使用的参考文献(例如)final尽可能多地使用,我想知道它有多重要.这主要是在方法参数和局部变量的上下文中,而不是最终方法或类.对于常数,它显然是有道理的.
一方面,编译器可以进行一些优化,这使得程序员的意图更加清晰.另一方面,它增加了详细程度,优化可能是微不足道的.
这是我应该努力记住的事情吗?
在Java中,您可以使用final关键字限定局部变量和方法参数.
public static void foo(final int x) {
final String qwerty = "bar";
}
Run Code Online (Sandbox Code Playgroud)
这样做会导致无法在方法体中重新分配x和qwerty.
这种做法使你的代码向不变性的方向推动,这通常被认为是一个加分.但是,它也会使代码混乱,"最终"出现在各处.您对Java中的局部变量和方法参数的final关键字有何看法?
比较这种方法:
void doStuff(String val) {
if (val == null) {
val = DEFAULT_VALUE;
}
// lots of complex processing on val
}
Run Code Online (Sandbox Code Playgroud)
...对于这种方法:
void doStuff(String origVal) {
String val = origVal;
if (val == null) {
val = DEFAULT_VALUE;
}
// lots of complex processing on val
}
Run Code Online (Sandbox Code Playgroud)
对于前一种方法,Eclipse会发出警告"不应分配参数'val'".为什么?
在我看来,前者更清洁.首先,它并没有迫使我想出两个好名字val(想出一个好的名字就足够了).
(注意:假设val封闭类中没有命名的字段.)
我一直在使用PMD帮助发现我的Java代码中的潜在问题,我一直在寻找它的建议,分为有用的,特殊的和"WTF ?!".
它一直告诉我要做的事情之一就是将final关键字用于字面上我可以附加的每个变量,包括输入参数.对于实际的常数,这似乎是明智的,但对于其他东西,它只是让我感到奇怪,甚至可能适得其反.
挂final在每个变量声明上是否有具体的优点/缺点?
我们知道最终制作字段通常是个好主意,因为我们获得了线程安全性和不变性,这使得代码更易于推理.我很好奇是否有相关的性能成本.
Java内存模型保证了这一点final Field Semantics:
在该对象完全初始化之后只能看到对象引用的线程可以保证看到该对象的最终字段的正确初始化值.
这意味着对于像这样的类
class X {
X(int a) {
this.a = a;
}
final int a;
static X instance;
}
Run Code Online (Sandbox Code Playgroud)
每当线程1创建这样的实例
X.instance = new X(43);
while (true) doSomethingEventuallyEvictingCache();
Run Code Online (Sandbox Code Playgroud)
和线程2看到它
while (X.instance == null) {
doSomethingEventuallyEvictingCache();
}
System.out.println(X.instance.a);
Run Code Online (Sandbox Code Playgroud)
它必须打印43.如果没有final修饰符,JIT或CPU可以重新排序存储(第一个存储X.instance然后设置a=43),线程2可以看到默认初始化值并打印0.
当JIT看到final它显然不会重新排序.但它也必须强制CPU遵守命令.是否存在相关的性能损失?
我遇到这种情况,我需要解析String到int,我不知道该怎么做了NumberFormatException.当我没有抓住它时,编译器不会抱怨,但我只是想确保我正确处理这种情况.
private int getCurrentPieceAsInt() {
int i = 0;
try {
i = Integer.parseInt(this.getCurrentPiece());
} catch (NumberFormatException e) {
i = 0;
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
我想简化这样的代码.编译器没有问题,但线程死了NumberFormatException.
private int getCurrentPieceAsInt() {
int i = 0;
i = Integer.parseInt(this.getCurrentPiece());
return i;
}
Run Code Online (Sandbox Code Playgroud)
Google CodePro希望我以某种方式记录异常,我同意这是最佳做法.
private int getCurrentPieceAsInt() {
int i = 0;
try {
i = Integer.parseInt(this.getCurrentPiece());
} catch (NumberFormatException e) {
i = 0;
e.printStackTrace();
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
我希望此方法0在当前片段不是数字或无法解析时返回.当我没有 …
我有一个变量,它不应该在初始化后改变它的值,所以我想把它定义为最终变量.
问题是变量必须在try块内初始化,所以我遇到以下麻烦:
我有以下代码:
Connection conn = null;
try {
conn = getConn(prefix);
[...do some stuff with conn...]
} catch (Exception e) {
throw new DbHelperException("error opening connection", e);
} finally {
closeConnection(conn);
}
Run Code Online (Sandbox Code Playgroud)
如果我将变量声明为final,而不将其初始化为null,则会在finally块上得到"局部变量conn可能尚未初始化".另一方面,如果我将其声明为final并将其初始化为null,则会在try块中收到错误"无法分配最终局部变量conn".
编辑:在lxx回答后,我来到这个版本
try {
final Connection conn = conn = getConn(prefix);
try {
return selectAll(conn, sql, params);
} catch (Exception e) {
throw new DbHelperException("error executing query", e);
} finally {
closeConnection(conn);
}
} catch (Exception e) {
throw new DbHelperException("error opening connection", e);
}
Run Code Online (Sandbox Code Playgroud)
那应该是这样做的方法吗?
- …
我知道编译器如何解释Java中的final关键字,但是我们应该如何解释它的含义呢?应该是:
1)此变量无法更改(例如内部类使用)
要么
2)我不打算更改此变量(可能对成员变量有一些优化优势).
我问的是因为我已经处理了默认情况下所有内容都被声明为final的代码(上面的选项2),在我看来,这会使关键字贬值并隐藏真正无法改变的值!声明变量最终还有性能优势吗?