Missing return statement in a non-void method compiles
我遇到了一种情况,一个非void方法缺少一个返回语句,代码仍然在编译。我知道while循环之后的语句是不可访问的(死代码),并且永远不会被执行。但是为什么编译器甚至不警告返回某些内容呢?或者,为什么一种语言会允许我们有一个具有无限循环且不返回任何内容的非空方法?
1 2 3 4 5 6 | public int doNotReturnAnything() { while(true) { //do something } //no return statement } |
如果在while循环中添加break语句(甚至是有条件语句),编译器会抱怨一些臭名昭著的错误:eclipse中的
1 2 3 4 5 6 7 | public int doNotReturnAnything() { while(true) { if(mustReturn) break; //do something } //no return statement } |
这对Java和C语言都是正确的。
Why would a language allow us to have a non-void method having an infinite loop and not returning anything?
非空方法的规则是返回的每个代码路径都必须返回一个值,并且该规则在您的程序中得到满足:返回的代码路径中有零个返回值。规则不是"每个非空方法都必须有返回的代码路径"。
这使您能够编写存根方法,如:
1 2 3 4 | IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } |
这是一个非无效的方法。为了满足接口,它必须是非空方法。但是,让这个实现非法似乎很愚蠢,因为它不返回任何东西。
你的方法因为EDOCX1(记住,
Why doesn't the compiler even warn about returning something?
因为编译器没有很好的证据证明代码是错误的。有人写了《以东记》1(2),似乎做那件事的人知道他们在做什么。
Where can I read more about reachability analysis in C#?
请参阅我关于这个主题的文章,这里:
ATBG:事实上和法律上的可达性
您也可以考虑阅读C规范。
Java编译器足够聪明,可以找到不可访问的代码(EDOCX1,0,循环之后的代码)
由于无法访问,因此在此处(在
条件
1 2 3 4 5 6 7 8 9 | public int get() { if(someBoolean) { return 10; } else { return 5; } // there is no need of say, return 11 here; } |
由于布尔条件EDCOX1〔6〕只能评估EDCOX1、7或EDCOX1〔8〕,所以不需要在EDCOX1×10的条件下明确地提供EDCOX1 1,因为该代码是不可达的,Java不抱怨。
编译器知道
如果您的循环是在一个常量上执行的——编译器知道它是一个无限循环——这意味着无论如何,该方法都无法返回。
如果使用变量-编译器将强制执行规则:
这不会编译:
1 2 3 4 5 6 7 8 9 | // Define other methods and classes here public int doNotReturnAnything() { var x = true; while(x == true) { //do something } //no return statement - won't compile } |
Java规范定义了一个名为EDCOX1 OR 11的概念。不允许在代码中使用无法访问的语句(这是编译时错误)。您甚至不允许在while(true)语句中使用返回语句。
注意,虽然中止问题在一般情况下是不可决定的,但是不可到达语句的定义比仅仅中止更严格。它决定了一个程序绝对不会停止的非常具体的情况。理论上,编译器无法检测所有无限循环和不可访问的语句,但它必须检测规范中定义的特定情况(例如,
在类型理论中,有一个称为底部类型的东西,它是所有其他类型的子类。用于表示不终止。(异常可以算作一种不终止——您不能通过普通路径终止。)
所以从理论上讲,这些非终止的语句可以被认为是返回一些底部类型的东西,它是int的一个子类型,所以您可以从类型的角度得到返回值。一个类型可以是包括int在内的所有其他类型的子类,这是完全可以理解的,因为实际上您从未返回过一个类型。
在任何情况下,无论是否通过显式类型理论,编译器(编译器编写器)都认识到在非终止语句后请求返回值是愚蠢的:在任何情况下都不可能需要该值。(当编译器知道某个东西不会终止,但看起来您希望它返回某个东西时,让它警告您可能会很好。但对于样式检查程序来说,这是最好的选择,因为可能由于其他原因(例如子类化),您需要这样的类型签名,但您确实希望不终止。
编译器足够聪明,可以发现您的
所以编译器不能为你考虑。它无法猜出你为什么写这段代码。同样表示方法的返回值。如果您不使用方法的返回值,Java不会抱怨。
所以,要回答你的问题:
编译器会分析您的代码,在发现没有执行路径会导致函数的结尾脱落后,用OK结束。
无限循环可能是有正当理由的。例如,许多应用程序使用无限主循环。另一个例子是Web服务器,它可以无限期地等待请求。
在任何情况下,函数都不能在不返回适当值的情况下到达其末尾。因此,编译器没有什么可抱怨的。
Visual Studio有智能引擎来检测您是否键入了返回类型,那么它应该在函数/方法中有一个带有的返回语句。
在PHP中,如果没有返回任何内容,则返回类型为true。如果没有返回任何内容,编译器将获取1。
就此而言
1 2 3 4 5 6 | public int doNotReturnAnything() { while(true) { //do something } //no return statement } |
编译器知道虽然语句本身具有内嵌性,所以不考虑它。如果在while表达式中编写条件,PHP编译器将自动获得true。
但在vs的情况下,它不会返回堆栈中的错误。
"为什么编译器甚至不警告返回某些内容?或者,为什么一种语言会允许我们有一个具有无限循环且不返回任何内容的非空方法?".
此代码在所有其他语言中也有效(可能除了haskell!)因为第一个假设是我们"故意"写一些代码。
在某些情况下,此代码可能完全有效,例如将其用作线程;或者如果它返回
您的while循环将永远运行,因此不会在while之外出现;它将继续执行。因此,while的外部部分是不可到达的,并且没有书面返回的意义。编译器足够智能,可以确定哪些部分是可访问的,哪些部分不是。
例子:
1 2 3 4 5 6 7 8 9 | public int xyz(){ boolean x=true; while(x==true){ // do something } // no return statement } |
上面的代码不会编译,因为在while循环体中可能会修改变量x的值。所以这使得while循环的外部部分可以访问!因此编译器将抛出一个错误"未找到返回语句"。
编译器没有足够的智能(或者说是懒惰的;)来判断x的值是否会被修改。希望这一切都能解决。
我可能错了,但有些调试器允许修改变量。这里,虽然x不是由代码修改的,它将由JIT进行优化,但是可以将x修改为false,并且方法应该返回一些内容(如果C调试器允许这样做的话)。
the specifics of the Java for this(which are probably房屋房屋# similar to the Very C)are to do with how the Java编译器determines method is to if a可以返回。P></
专门开发,the rules are that a method with a must not be to Return型能全面和完整normally必备abruptly(instead abruptly总是显示在表或在返回路径安8.4.7 JLS例外)。P></
If a method is declared to have a return type, then a compile-time
error occurs if the body of the method can complete normally.
In other words, a method with a return type must return only by using
a return statement that provides a value return; it is not allowed to
"drop off the end of its body".
编译器如何看,看是否正规the the rules is possible终止基于定义在声明unreachable JLS 14.21 defines the rules for as恩也正常完成。P></
notably,the rules for unreachable报表做特殊的房屋,一环有一个定义为:
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.
我知道我
这些规则的声明,你的
出现:P></
1 2 3 4 5 6 7 | // I have a compiler error! public boolean testReturn() { final boolean condition = true; if (condition) return true; } |
与:P></
1 2 3 4 5 6 7 8 9 10 | // I compile just fine! public boolean testReturn() { final boolean condition = true; while (condition) { return true; } } |
那么is the reason for the区分两个兴趣和欲望,is to the to allow for that do not旗条件汇编编译器错误原因(from the JLS):P></
One might expect the if statement to be handled in the following
manner:
An if-then statement can complete normally iff at least one of the
following is true:
The if-then statement is reachable and the condition expression is not
a constant expression whose value is true.The then-statement can complete normally.
The then-statement is reachable iff the if-then statement is reachable
and the condition expression is not a constant expression whose value
is false.An if-then-else statement can complete normally iff the then-statement
can complete normally or the else-statement can complete normally.
The then-statement is reachable iff the if-then-else statement is
reachable and the condition expression is not a constant expression
whose value is false.The else-statement is reachable iff the if-then-else statement is
reachable and the condition expression is not a constant expression
whose value is true.This approach would be consistent with the treatment of other control
structures. However, in order to allow the if statement to be used
conveniently for"conditional compilation" purposes, the actual rules
differ.As an example, the following statement results in a compile-time
error:
while (false) { x=3; } because the statementx=3; is not reachable;
but the superficially similar case:
if (false) { x=3; } does not result in a compile-time error. An
optimizing compiler may realize that the statementx=3; will never be
executed and may choose to omit the code for that statement from the
generated class file, but the statementx=3; is not regarded as
"unreachable" in the technical sense specified here.The rationale for this differing treatment is to allow programmers to
define"flag variables" such as:
static final boolean DEBUG = false; and then write code such as:
if (DEBUG) { x=3; } The idea is that it should be possible to change
the value of DEBUG from false to true or from true to false and then
compile the code correctly with no other changes to the program text.
为什么does the statement(conditional霹雳在编译错误?P></
as quoted in the rules reachability while循环回路,也完全可以normally if it contains a statement reachable霹雳。reachability since the rules for the of an
if the