谢邀。这个问题我之前也有过些许疑惑,借题主这个问题简单说一下。
比较简单的理解方式是「执行路径」。
我们在中学数学里学过,一个算法的流程有三种:顺序、分支和循环。当算法结束时,我们应当停在某个终点,而终点的数量则与这三种结构之间的组合有关。
顺序结构本身就代表着一个终点,它不会影响终点的数量;
分支结构一定会增加终点的数量,有N个可能性的分支会给整个算法增加N-1个终点;
循环结构比较复杂,它可能不影响终点数量,也可能减少终点数量,区别就在于它是否能结束。能结束的循环就是一个拉长的顺序结构,不影响终点数量;而不能结束的循环会减少一个终点的数量。
理解了终点的数量,再看Java的规定。Java语言标准规定,所有返回类型不是void的方法,都不允许正常完成。
什么是正常完成呢? 一个没有return、throw、break等提前结束语句的方法就是可以正常完成的。我们平常写return觉得它是正常返回,但对语言本身来说,它属于非正常地打断执行流程,强行跳转回调用方法的过程。
那无限循环的while语句属不属于正常完成呢?不属于。Java语言规定A while statement can complete normally iff at least one of the following is true:
- The while statement is reachable and the condition expression is not a constant expression (§15.28) with value true.
- There is a reachable break statement that exits the while statement.
也就是说,带有常量表达式true的while语句是不可正常完成的,满足返回值不为void的标准。
问题还没有解决。我们平常写个声明返回类型是int的方法,如果返回个double类型的结果,编译器肯定不会通过,因为double不是int的子类型。但为什么编译器就允许while(true)出现这种类型不匹配呢?
其实这种类型不匹配的情况在Java里还有不少,我们先看另一个例子:
public int positiveValue(int value) {
if (value < 0)
throw IllegalArgumentException();
return value;
}
这个函数当然是正确的,不过,当value < 0时,它的返回值满足返回类型int吗?实际上,把声明里的int改成任何其他类型都是正确的。那也就是说, throw的返回类型应该是任何类型的子类型, 这样它才能满足非正常结束所有函数的要求。
如果有一个类型是所有类型的子类型,我们就把它叫做底类型(Bottom Type)。
Java的类型系统里没有这个类型,所以比较难以捉摸,但在支持函数式编程的语言里一般都会有这种类型,比如Kotlin里的Nothing和Rust里的!就是底类型。
这时我们就可以比较完善地解释while(true)的问题了, 一个没有break的while(true)语句实际上具有底类型,因此编译器能够允许它存在于返回值不为void的语句里。