问题 “但是编译器不知道这个” - 这是什么意思?


我在网上遇到过这样的代码和评论 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(...)?什么原因?


2507
2018-01-11 19:31


起源

@YCF_L不是真的...... stackoverflow.com/a/48215005/1059372 - Eugene


答案:


也许,它只是避免代码重复,因为否则它会是这样的:

new IndexOutOfBoundsException(outOfBoundsMessage(..., ...)) 

outOfBounds* 方法是 private,所以按照设计,有人应该调用包装器 return Preconditions.checkIndex(index, length, null)


7
2018-01-11 19:42



是的,避免代码重复。努力集中所有这些索引检查和异常消息构造。这不仅影响集合实现和 Arrays 实用方法,还有NIO缓冲区, CharSequence 实现等等。很多地方,很多代码重复。请注意,这是一个 新的API方法 允许您的应用程序参与此中央处理。不过,我会用 throw new AssertionError() 代替 return null; 这里… - Holger
主人@Holger,感谢您对我的回答和您的评论。在这个问题中也非常需要你的权威意见: stackoverflow.com/questions/48227496/... - Andremoniy
@Holger如果你不介意的话,我会说 - Eugene


实现似乎更多的是面向设计而不仅仅是功能。

其原因主要可能是 Preconditions.checkIndex 被标记为 @HotSpotIntrinsicCandidate 这意味着在内部使用此方法时会寻求代码性能改进。

另外,可以注意到所有不可变列表 - 包含0(空),1,2或N个元素,使用工厂方法创建 of 利用了 Objects.checkIndex(int index, int length) 最终依赖于上述方法调用可能会进行一些内部优化。


简要说明 HotSpotIntrinsicCandidate 来自图书馆: -

@HotSpotIntrinsicCandidate 注释特定于    HotSpot虚拟机。它表示注释的方法可能(但不保证)由HotSpot VM中介化。

如果HotSpot VM替换带注释的方法,则会使方法本身化   手写汇编和/或手写编译器IR的方法    - 编译器内在 - 以提高性能。

@HotSpotIntrinsicCandidate 注释是Java的内部   图书馆,因此不应该有任何相关性   应用代码。


3
2018-01-12 02:00



如果你提到的话 @HotSpotIntrinsicCandidate 你可以提到的 @ForceInline 对于 Objects.checkIndex。此外,这很有趣 怎么样 究竟是一个CPU来优化这个内在的调用;我不知道顺便说一句 - Eugene
@Eugene ForceInline 似乎专注于忽略注释方法的指标,因此避免将其纳入讨论。没有深入研究实施 HotSpotIntrinsicCandidate 我自己也是。 - nullpointer
在实现下没什么可看的...... :)它只是一个注释,你必须挖掘jvm源文件,看看是什么 尤其  完成那个方法...... - Eugene


除非我在这里遗漏了一些明显的东西,否则这更简单。它与以下内容相同:

// 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 所以它需要一个 return 声明 s()。同样的事情发生在 switch 枚举的陈述,你必须提供一个 throw;即使你已经处理了这个枚举的所有案例。


这个代码btw用于 List0,打电话没有意义 get(x),因为列表中没有元素可靠。


3
2018-01-11 20:05



你总是可以写 public String s() { throw new RuntimeException("aaa"); } 什么是100%有效和可编译的代码 - Andremoniy
@Andremoniy对,但我不明白你的观点 - Eugene