Java Objects.requireNonNull 是否比旧方式效率低?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29864642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:43:30  来源:igfitidea点击:

Is Objects.requireNonNull less efficient than the old way?

javaperformancenull

提问by Bobulous

Since JDK 7 I've been happily using the method it introduced to reject nullvalues which are passed to a method which cannot accept them:

自 JDK 7 以来,我一直很高兴使用它引入的方法来拒绝null传递给无法接受它们的方法的值:

private void someMethod(SomeType pointer, SomeType anotherPointer) {
    Objects.requireNonNull(pointer, "pointer cannot be null!");
    Objects.requireNonNull(anotherPointer, "anotherPointer cannot be null!");
    // Rest of method
}

I think this method makes for very tidy code which is easy to read, and I'm trying to encourage colleagues to use it. But one (particularly knowledgeable) colleague is resistant, and says that the old way is more efficient:

我认为这种方法使代码非常整洁,易于阅读,我正在努力鼓励同事使用它。但是一位(尤其是知识渊博的)同事对此表示反对,并表示旧方法更有效:

private void someMethod(SomeType pointer, SomeType anotherPointer) {
    if (pointer == null) {
        throw new NullPointerException("pointer cannot be null!");
    }
    if (anotherPointer == null) {
        throw new NullPointerException("anotherPointer cannot be null!");
    }
    // Rest of method
}

He says that calling requireNonNullinvolves placing another method on the JVM call stack and will result in worse performance than a simple == nullcheck.

他说调用requireNonNull涉及在 JVM 调用堆栈上放置另一个方法,并且会导致比简单== null检查更差的性能。

So my question: is there any evidenceof a performance penalty being incurred by using the Objects.requireNonNullmethods?

所以我的问题是:是否有任何证据表明使用这些Objects.requireNonNull方法会导致性能损失?

采纳答案by T.J. Crowder

Let's look at the implementation of requireNonNullin Oracle's JDK:

我们来看看requireNonNull在Oracle的JDK中的实现:

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

So that's very simple. The JVM (Oracle's, anyway) includes an optimizing two-stage just-in-time compiler to convert bytecode to machine code. It will inline trivial methods like this if it can get better performance that way.

所以这很简单。JVM(无论如何都是 Oracle 的)包括一个优化的两阶段即时编译器,用于将字节码转换为机器码。如果它可以通过这种方式获得更好的性能,它将内联像这样的琐碎方法。

So no, not likely to be slower, not in any meaningful way, not anywhere that would matter.

所以不,不太可能变慢,不会以任何有意义的方式,不会在任何重要的地方。

So my question: is there any evidenceof a performance penalty being incurred by using the Objects.requireNonNullmethods?

所以我的问题是:是否有任何证据表明使用这些Objects.requireNonNull方法会导致性能损失?

The only evidence that would matter would be performance measurements of yourcodebase, or of code designed to be highly representative of it. You cantest this with any decent performance testing tool, but unless your colleague can point to a real-world example of a performance problem in your codebase related to this method (rather than a synthetic benchmark), I'd tend to assume you and he/she have bigger fish to fry.

唯一重要的证据是对您的代码库或设计为具有高度代表性的代码的性能测量。您可以使用任何合适的性能测试工具对此进行测试,但除非您的同事可以指出与此方法相关的代码库中性能问题的真实示例(而不是综合基准),否则我倾向于假设您和他/她有更大的鱼要煎。



As a bit of an aside, I noticed your sample method is a privatemethod. So only code your team is writing calls it directly. In those situations, you might look at whether you have a use case for assertionsrather than runtime checks. Assertions have the advantage of not executing in "released" code at all, and thus being faster than either alternative in your question. Obviously there are places you need runtime checks, but those are usually at gatekeeping points, public methods and such. Just FWIW.

顺便说一句,我注意到您的示例方法是一种private方法。因此,只有您的团队正在编写的代码才能直接调用它。在这些情况下,您可能会查看是否有断言用例而不是运行时检查。断言的优点是根本不在“已发布”代码中执行,因此比您问题中的任一替代方案都快。显然有些地方需要运行时检查,但通常在看门点、公共方法等。只是 FWIW。

回答by Crazyjavahacking

Your colleague is most likely wrong.

你的同事很可能是错的。

JVM is very intelligent and will most likely inline the Objects.requireNonNull(...)method. The performance is questionable but there will be definitely much more serious optimizations than this.

JVM 非常智能,很可能会内联该Objects.requireNonNull(...)方法。性能值得怀疑,但肯定会有比这更严重的优化。

You should use the utility method from JDK.

您应该使用 JDK 中的实用程序方法。

回答by Stephen C

If you want evidence... then the way to get it is to write a micro-benchmark.

如果你想要证据......那么获得它的方法是编写一个微基准。

(I recommend looking at the Calliper project first! Or JMH ... per Boris's recommendation. Either way, don't try and write a micro-benchmark from scratch. There are too many ways to get it wrong.)

(我建议先查看 Caliper 项目!或者 JMH ......根据鲍里斯的建议。无论哪种方式,都不要尝试从头开始编写微基准测试。有太多方法会出错。)

However, you can tell your colleague two things:

但是,您可以告诉您的同事两件事:

  • The JIT compiler does a good job of inlining small method calls, and it is likely that this will happen in this case.

  • If it didn't inline the call, the chances are that the difference in performance would only be a 3 to 5 instructions, and it is highly unlikely that it would make a significant difference.

  • JIT 编译器在内联小方法调用方面做得很好,在这种情况下很可能会发生这种情况。

  • 如果它没有内联调用,则性能差异很可能只有 3 到 5 条指令,而且极不可能产生显着差异。

回答by leventov

Formally speaking,your colleague is right:

正式地说,你的同事是对的:

  • If someMethod()or corresponding trace is not hot enough, the byte code is interpreted, and extra stack frame is created

  • If someMethod()is called on 9-th level of depth from hot spot, the requireNonNull()calls shouldn't be inlined because of MaxInlineLevelJVM Option

  • If the method is not inlined for any of the above reasons, argument by T.J. Crowder comes into play, if you use concatenation for producing error message

  • Even if requireNonNull()is inlined, JVM wastes time and space for performing this.

  • 如果someMethod()或 相应的跟踪不够热,则解释字节码,并创建额外的堆栈帧

  • 如果someMethod()在热点的第 9 层深度上requireNonNull()调用,则不应因JVM 选项而内联调用MaxInlineLevel

  • 如果由于上述任何原因未内联该方法,则 TJ Crowder 的参数将起作用,如果您使用连接来生成错误消息

  • 即使requireNonNull()是内联的,JVM 也会浪费时间和空间来执行此操作。

On the other hand, there is FreqInlineSizeJVM option, which prohibits inlining too big (in bytecodes) methods. The method's bytecodes is counted by themselves, without accounting size of methods, called within this method. Thus, extracting pieces of code into independent methods could be useful sometimes, in the example with requireNonNull()this extraction is made for you already.

另一方面,有FreqInlineSizeJVM 选项,它禁止内联过大(在字节码中)的方法。方法的字节码是自己计算的,不计算方法的大小,在这个方法中调用。因此,有时将代码片段提取到独立的方法中可能很有用,在示例中,requireNonNull()这种提取已经为您准备好了。

回答by richa ojha

Objects.requireNonNull is more optimised as if you this you are code reusability. Also in oracle requireNonNull si defined as

Objects.requireNonNull 更加优化,就好像您是代码可重用性一样。同样在 oracle requireNonNull si 中定义为

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
} 

so its already in bytecode.

所以它已经在字节码中了。

回答by punkstarman

As a general rule, readability and maintainability should trump optimization.

作为一般规则,可读性和可维护性应该胜过优化。

This rule safeguards against speculative optimization from people who think they know how a compiler works even though they have never even attempted to write one and they have never had a look inside one.

这条规则可以防止那些认为自己知道编译器如何工作的人的推测优化,即使他们从未尝试过编写编译器,也从未深入了解过编译器。

Your colleague is wrong unless they prove that the performance penalty is noticeable and untenable for users.

你的同事是错误的,除非他们证明性能损失对用户来说是明显且站不住脚的。

回答by Michael G

Effective Javaby Joshua Bloch

Joshua Bloch 的《Effective Java》

Item 67: Optimize judiciously

There are three aphorisms concerning optimization that everyone should know:

More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason—including blind stupidity.
—William A. Wulf [Wulf72]

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
—Donald E. Knuth [Knuth74]

We follow two rules in the matter of optimization:
Rule 1. Don't do it.
Rule 2 (for experts only). Don't do it yet—that is, not until you have a perfectly clear and unoptimized solution.
—M. A. Hymanson [Hymanson75]

第 67 条:明智地优化

每个人都应该知道的关于优化的三个格言:

以效率的名义(不一定实现它)比任何其他单一原因(包括盲目愚蠢)犯下的计算罪更多。
——威廉·A·伍尔夫 [Wulf72]

我们应该忘记小效率,比如大约 97% 的时间:过早的优化是万恶之源。
——唐纳德·E·克努斯 [Knuth74]

我们在优化问题上遵循两条规则:
规则 1. 不要这样做。
规则 2(仅适用于专家)。暂时不要这样做——也就是说,除非你有一个非常清晰且未经优化的解决方案。
——马·Hyman逊 [Hymanson75]

回答by mrts

Yes, there is evidence that the difference between manual nullcheck and Objects.requireNonNull()is negligible. OpenJDK commiter Aleksey Shipilev created benchmarking codethat proves this while fixing JDK-8073479, here is his conclusion and performance numbers:

是的,有证据表明手动null检查和手动检查之间的差异Objects.requireNonNull()可以忽略不计。OpenJDK 提交者 Aleksey Shipilev 创建了基准测试代码,在修复JDK-8073479 时证明了这一点,以下是他的结论和性能数据:

TL;DR: Fear not, my little friends, use Objects.requireNonNull.
       Stop using these obfuscating Object.getClass() checks,
       those rely on non-related intrinsic performance, potentially
       not available everywhere.

Runs are done on i5-4210U, 1.7 GHz, Linux x86_64, JDK 8u40 EA.

The explanations are derived from studying the generated code
("-prof perfasm" is your friend here), the disassembly is skipped
for brevity.


Out of box, C2 compiled:

Benchmark                  Mode  Cnt  Score   Error  Units
NullChecks.branch          avgt   25  0.588 ± 0.015  ns/op
NullChecks.objectGetClass  avgt   25  0.594 ± 0.009  ns/op
NullChecks.objectsNonNull  avgt   25  0.598 ± 0.014  ns/op

Object.getClass() is intrinsified.
Objects.requireNonNull is perfectly inlined.

where branch, objectGetClassand objectsNonNullare defined as follows:

其中branchobjectGetClassobjectsNonNull定义如下:

@Benchmark
public void objectGetClass() {
    o.getClass();
}

@Benchmark
public void objectsNonNull() {
    Objects.requireNonNull(o);
}

@Benchmark
public void branch() {
    if (o == null)  {
        throw new NullPointerException();
    }
}