“但编译器不知道这一点” - 这是什么意思?

11

我在 java.util.ImmutableCollections 类中遇到了这样一种代码和注释:

static final class List0<E> extends AbstractImmutableList<E> {
    ...
    @Override
    public E get(int index) {
        Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
        return null;                  // but the compiler doesn't know this
    } 
    ...
}

为什么不直接使用throw new IndexOutOfBoundsException(...)?原因是什么?

2
@YCF_L 不是很... https://dev59.com/flYM5IYBdhLWcg3w5zUg#48215005 - Eugene
3个回答

7
也许只是为了避免代码重复,否则可能会变成这样:
new IndexOutOfBoundsException(outOfBoundsMessage(..., ...)) 

但是outOfBounds*方法是private的,因此按照设计,某人应该调用像return Preconditions.checkIndex(index, length, null)这样的包装器。


7
是的,避免代码重复。现在有一个努力将所有这些索引检查和异常消息构建集中起来。这不仅影响集合实现和 Arrays 实用方法,还包括 NIO 缓冲区、CharSequence 实现等许多地方,存在大量的代码重复。请注意,这是一个新的API方法,允许您的应用程序参与到这个集中处理中。尽管如此,在这里我会使用throw new AssertionError()代替return null;... - Holger
大师@Holger,感谢您对我的回答的赞赏和附加评论。在这个问题中,您权威的意见也非常需要:https://dev59.com/NVYM5IYBdhLWcg3w5jRN - Andremoniy

3

除非我在这里漏了什么显而易见的东西,否则这就简单多了。这与以下内容相同:

// this will not compile, *even* if test throws the Exception always
public String s() {
    test(); 
}

private void test() {
    throw new RuntimeException("just because");
}

编译器无法确定test总是会抛出RuntimeException,因此需要在s()中提供一个return语句。在枚举类型的switch语句中也会发生同样的情况,即使您已经处理了该枚举的所有情况,仍需要提供throw语句。
顺便说一下,这段代码用于List0中,在这里调用get(x)没有意义,因为这个List肯定没有元素。

你可以随时编写 public String s() { throw new RuntimeException("aaa"); } 这段代码,它是100%有效且可编译的。 - Andremoniy

2
实现似乎更加注重设计而不仅仅是功能。这主要是因为 Preconditions.checkIndex 被标记为 @HotSpotIntrinsicCandidate,这意味着在内部使用该方法时正在寻求代码性能改进。此外,可以注意到所有不可变列表 - 包含 0(空)、1、2 或 N 个元素,使用工厂方法 of 创建时都使用 Objects.checkIndex(int index, int length),最终依赖于上述方法调用来可能进行一些内部优化。
库中的 HotSpotIntrinsicCandidate 简介:

@HotSpotIntrinsicCandidate 注释特定于 HotSpot 虚拟机。它表示一个带有注释的方法可能会被 HotSpot VM 内部化(但不能保证)。

如果 HotSpot VM 用手写汇编和/或手写编译器 IR 替换了带有注释的方法,则该方法将被内部化 -- 编译器内置 -- 以提高性能。

@HotSpotIntrinsicCandidate 注释对于应用程序代码没有任何关联,它是 Java 库中的内部注释。


如果你提到了@HotSpotIntrinsicCandidate,你可以为Objects.checkIndex提供@ForceInline。此外,这很有趣,因为CPU将如何优化这个内部调用;我不知道。 - Eugene
@Eugene ForceInline似乎专注于忽略已注释方法的度量,因此避免将其纳入讨论。我自己还没有深入研究过HotSpotIntrinsicCandidate的实现。 - Naman
1
在实现下面并没有太多可看的... :) 这只是一个注释,你需要挖掘JVM源文件并查看该方法特别做了什么... - Eugene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接