int 上的余数运算符导致 java.util.Objects.requireNonNull?

Rob*_*bAu 12 java performance modulo primitive-types null-check

我试图从某些内部方法中获得尽可能多的性能。

Java代码是:

List<DirectoryTaxonomyWriter> writers = Lists.newArrayList();
private final int taxos = 4;

[...]

@Override
public int getParent(final int globalOrdinal) throws IOException {
    final int bin = globalOrdinal % this.taxos;
    final int ordinalInBin = globalOrdinal / this.taxos;
    return this.writers.get(bin).getParent(ordinalInBin) * this.taxos + bin; //global parent
}
Run Code Online (Sandbox Code Playgroud)

在我的分析器中,我看到 1% 的 CPU 支出java.util.Objects.requireNonNull,但我什至不称之为。在检查字节码时,我看到了:

 public getParent(I)I throws java/io/IOException 
   L0
    LINENUMBER 70 L0
    ILOAD 1
    ALOAD 0
    INVOKESTATIC java/util/Objects.requireNonNull (Ljava/lang/Object;)Ljava/lang/Object;
    POP
    BIPUSH 8
    IREM
    ISTORE 2
Run Code Online (Sandbox Code Playgroud)

所以编译器会生成这个(没用的?)检查。我在原语上工作,null无论如何都不能,那么编译器为什么会生成这一行?这是一个错误吗?还是“正常”行为?

(我可能会使用位掩码,但我只是好奇)

[更新]

  1. 运营商似乎与它无关(请参阅下面的答案)

  2. 使用 eclipse 编译器(4.10 版),我得到了更合理的结果:

    public getParent(I)I 抛出 java/io/IOException 
       L0
        LINENUMBER 77 L0
        负载 1
        图标_4
        国际电联
        2号店
       L1
        LINENUMBER 78 升

所以这更合乎逻辑。

maa*_*nus 3

为什么不?

假设

class C {
    private final int taxos = 4;

    public int test() {
        final int a = 7;
        final int b = this.taxos;
        return a % b;
    }
}
Run Code Online (Sandbox Code Playgroud)

c.test()像where这样的调用c被声明为 as ,当is时C 必须抛出。你的方法相当于cnull

    public int test() {
        return 3; // `7 % 4`
    }
Run Code Online (Sandbox Code Playgroud)

因为您只使用常量。由于test是非静态的,因此必须进行检查。通常,当访问字段或调用非静态方法时,它会隐式完成,但您不这样做。因此需要进行显式检查。一种可能性是致电Objects.requireNonNull

字节码

不要忘记字节码基本上与性能无关。的任务javac是生成一些字节码,其执行与源代码相对应。它并不意味着进行任何优化,因为优化后的代码通常更长且更难分析,而字节码实际上是优化 JIT 编译器的源代码。所以javac预计保持简单......

性能

在我的分析器中,我看到有 1% 的 CPU 支出java.util.Objects.requireNonNull

我首先会责怪分析器。分析 Java 非常困难,您永远无法期望完美的结果。

您可能应该尝试将该方法设为静态。您当然应该阅读这篇关于空检查的文章