在这种简单的情况下,即时编译器可能会忽略对象分配,或者至少将其分配在堆栈上,因此开销可以忽略不计。
这是一个小基准:
public abstract class Benchmark {
final String name;
public Benchmark(String name) {
this.name = name;
}
@Override
public String toString() {
return name + "\t" + time() + " ns / iteration";
}
private BigDecimal time() {
try {
// automatically detect a reasonable iteration count (and trigger just in time compilation of the code under test)
int iterations;
long duration = 0;
for (iterations = 1; iterations < 1_000_000_000 && duration < 1_000_000_000; iterations *= 2) {
long start = System.nanoTime();
run(iterations);
duration = System.nanoTime() - start;
cleanup();
}
return new BigDecimal((duration) * 1000 / iterations).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* Executes the code under test.
* @param iterations
* number of iterations to perform
* @return any value that requires the entire code to be executed (to
* prevent dead code elimination by the just in time compiler)
* @throws Throwable
* if the test could not complete successfully
*/
protected abstract Object run(int iterations) throws Throwable;
/**
* Cleans up after a run, setting the stage for the next.
*/
protected void cleanup() {
// do nothing
}
public static void main(String[] args) throws Exception {
Integer[] a = {null, -1, null, 1}; // mix nulls and real values
System.out.println(new Benchmark("Optional") {
@Override
protected Object run(int iterations) throws Throwable {
int[] sum = {0};
for (int i = 0; i < iterations; i++) {
Optional.ofNullable(a[i & 3]).filter(k -> k > 0).ifPresent(k -> sum[0] += k);
}
return sum[0];
}
});
System.out.println(new Benchmark("if != null") {
@Override
protected Object run(int iterations) throws Throwable {
int[] sum = {0};
for (int i = 0; i < iterations; i++) {
var k = a[i & 3];
if (k != null && k % 2 != 0) {
sum[0] += k;
}
}
return sum[0];
}
});
}
}
这表明使用 Optional 的开销约为 1 ns,即现代 CPU 每秒可以构造和评估大约 10 亿个 Optional 对象。在除了最极端和人为的工作负载之外,使用Optional 不会对性能产生足够的影响,以至于人类可以注意到。
因此,使用Optional 的决定不应以性能考虑为指导,而应以哪个版本更清晰、更简单地表达自己为指导。
在这种情况下,我认为 if 语句实际上更具可读性。当然,您已将所有内容压缩到一行,但您可以使用 if 语句来做同样的事情:
if (item != null && item.getCrystal() == Crystal.A) player.getInventory().addItem(inventoryItem);
如果你这样做,你会注意到 if 语句实际上比你的版本更短更切题:
Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A).ifPresent(k -> player.getInventory.addItem(i));
当然,在实际代码中,您可能希望行保持合理的短,所以比较是
if (item != null && item.getCrystal() == Crystal.A) {
player.getInventory().addItem(inventoryItem);
}
对
Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A)
.ifPresent(k -> player.getInventory.addItem(i));
再次,我发现第一个版本更具可读性,因为它包含的单词更少。