内部候选静态方法引用在一段时间后消失了吗?

Intrinsic candidate static method reference disappears after a while?

我有以下 Comparator 实现:

private static final class ValueComparator<Value_, Point_ extends Comparable<Point_>> implements Comparator<Value_> {

    private final Function<Value_, Point_> indexFunction;

    public ValueComparator(Function<Value_, Point_> indexFunction) {
        this.indexFunction = Objects.requireNonNull(indexFunction);
    }

    @Override
    public int compare(Value_ o1, Value_ o2) {
        if (o1 == o2) {
            return 0;
        }
        Point_ point1 = indexFunction.apply(o1);
        Point_ point2 = indexFunction.apply(o2);
        if (point1 == point2) {
            return 0;
        }
        int comparison = point1.compareTo(point2);
        if (comparison != 0) {
            return comparison;
        }
        // Identity Hashcode for duplicate protection; we must always include duplicates.
        // Ex: two different games on the same time slot
        int identityHashCode1 = System.identityHashCode(o1);
        int identityHashCode2 = System.identityHashCode(o2);
        return Integer.compare(identityHashCode1, identityHashCode2);
    }
}

这段代码运行了一段时间,然后突然抛出一个 NPE - indexFunction 不知何故变成了 null,即使它在构造函数中被检查为非空。

显然,这让我很烦,所以我去寻找,我发现 indexFunctionMath::abs,一个对静态方法的引用。 java.lang.Math.abs(int)@HotSpotIntrinsicCandidate.

这是否意味着 HotSpot 在某个时刻内化了方法,因此方法引用变得无效?我该如何保护自己免受此类事情的侵害?

$ java -version
openjdk version "11.0.12" 2021-07-20
OpenJDK Runtime Environment Temurin-11.0.12+7 (build 11.0.12+7)
OpenJDK 64-Bit Server VM Temurin-11.0.12+7 (build 11.0.12+7, mixed mode)

您 运行 遇到了一个错误,看到了一些您不理解的东西,并且显然在您的机智尽头并且无法理解您的代码如何受到指责,放大了您没有理解的东西'明白了:一定是这样!

通常这不是调试的好方法。 Java 错误或设计白痴解释你的问题的几率是无穷小的(因为说实话,如果 final 变量 运行 突然消失在稀薄的空气中,或者以某种方式变成 null ,或者更糟的是,保持原样,但任何与之交互的尝试都会导致 'oh the function disappeared',并且由 NullPointerException 处理,这很愚蠢)。这是使用具有 这个 许多用户的语言的优势之一。您是第一个 运行 的几率非常低。

我知道,由于现已确认的 JVM 错误,我输掉了一次 Google Code Jam 挑战。所以它 可以 发生。但胜算微乎其微。

Does that mean that HotSpot has, at some point, intrinsified the method and therefore the method reference became invalid?

没有。那是不可能的。这不是 'intrinsic' 的意思。

How do I protect myself against this sort of thing?

你不能,这很好,因为你不必 - 这种情况永远不会发生。

检查堆栈跟踪。 indexFunction 不为空。但是,索引函数可能 本身 抛出 NPE,如果 o1 为 null 而 o2 不为 null,则可能会抛出 NPE,反之亦然。

单独说明一下,您最初为什么要编写这段代码?这已经存在于 JVM 中:

而不是调用:

new ValueComparator(x -> x.getPoint());

您只需致电:

Comparator.comparing(x -> x.getPoint()).thenComparingInt(System::identityHashCode);

事实证明,答案要简单得多,也不那么耸人听闻。 indexFunction 的参数为 null,并且函数期望 int,NPE 来自拆箱。在这种情况下,NPE 仍然指向 indexFunction,而不是其中的一些代码,这最初让我走上了一条完全错误的道路。

显然我没有像我想象的那样彻底检查我的输入。菜鸟错误,结案。