简体   繁体   English

将 null 检查替换为可选

[英]Replace null check with Optional

I would like to know since i'm fan of java 14 if replacing null checks with Optional.ofNullable is safe for this language.我想知道,因为我是 java 14 的粉丝,如果用 Optional.ofNullable 替换 null 检查对于这种语言是安全的。 I know a simple null check doesn't cost any memory while new creating new objects like optional cost but i guess it has zero performance impact or memory impact.我知道一个简单的 null 检查不会花费任何 memory 而新创建的新对象(如可选成本)但我猜它对性能的影响为零或 memory 影响。 Can someone enlight me?有人可以启发我吗?

The code for my game was like:我的游戏代码是这样的:

if (item!= null)
{
   if (item.getCrystal() == Crystal.A)
   {
     player.getInventory().addItem(inventoryItem);
   }
}

to something which i enjoy and i find cool我喜欢的东西,我觉得很酷

Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A).ifPresent(k -> player.getInventory.addItem(i));

Can someone enlight me that i'm ok with it?有人能告诉我我没问题吗? Maybe is cool but cost a lot?也许很酷但要花很多钱? I don't know.我不知道。 Thanks a lot.非常感谢。

In simple cases like this, the just in time compiler can likely elide the object allocation, or at least allocate it on the stack, so the overhead is negligible.在像这样的简单情况下,即时编译器可能会忽略 object 分配,或者至少将其分配在堆栈上,因此开销可以忽略不计。

Here's a small benchmark:这是一个小基准:

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]; 
            }
        });
    }
}

This shows that the overhead of using an Optional is about 1 ns, ie a modern CPU can construct and evaluate about 1 billion Optional objects per second.这表明使用Optional的开销约为 1 ns,即现代 CPU 每秒可以构造和评估大约 10 亿个Optional对象。 In all but the most extreme and contrived of workloads, the use of Optional will not affect performance enough for humans to notice.除了最极端和人为的工作负载之外,使用Optional不会影响性能,足以让人们注意到。

The decision to use Optional should therefore not be guided by performance considerations, but by which version allows yourself to express yourself more clearly and simply.因此,使用Optional的决定不应以性能考虑为指导,而应根据哪个版本让自己更清晰、更简单地表达自己。

In this case, I'd argue that the if statement is actually more readable.在这种情况下,我认为 if 语句实际上更具可读性。 Sure, you've squashed everything onto a single line, but you could do the same with an if statement:当然,您已将所有内容压缩到一行,但您可以使用 if 语句执行相同操作:

if (item != null && item.getCrystal() == Crystal.A) player.getInventory().addItem(inventoryItem);

If you do that, you'll notice that the if statement is actually shorter and more to the point than your version:如果你这样做,你会注意到 if 语句实际上比你的版本更短,更重要:

Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A).ifPresent(k -> player.getInventory.addItem(i));

Of course, in real code you'll probably want to keep your lines reasonably short, so the comparison is当然,在实际代码中,您可能希望保持行相当短,所以比较是

if (item != null && item.getCrystal() == Crystal.A) {
    player.getInventory().addItem(inventoryItem);
}

vs对比

Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A)
    .ifPresent(k -> player.getInventory.addItem(i));

Again, I find the first version more readable, because it contains fewer words.同样,我发现第一个版本更具可读性,因为它包含的单词更少。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM