Java循环编译错误

时间:2015-07-09 20:13:21

标签: java loops

有人可以向我解释一下吗?首先,我知道为什么这个代码

String getName(){
    for(;;){}
}

会违反return类型方法:它是无限的,但为什么此代码需要最终返回值

String getName(){
    for(;i < limit; i++){// i is already defined
        if(someArrayList.get(i).isDead)
            continue;
        return someArrayList.get(i).name;
    }
    //needs a final return
}

返回值存在于循环内部并返回getName()方法的值,那么原因是什么?另一个post建议如果循环对我的条件是负面的,那么我就这样改写:

String getName(){
    for(; i < 10; i++){// i is already defined
        if((i+1) == limit){
            if(!someArrayList.get(i).isDead)
                return "";
        }else{
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
    }
    // needs a final return
}

相同的编译时错误,即使我在for循环条件中将i重新定义为0,所以我的i变为零,如果内部条件检出否定我自己处理。总而言之,如果我将它嵌套在无限循环中,那就没关系。

String getName(){
    for(;;){
        for(; i < limit; i++){// i is already defined
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
    }
}

是因为它有射程吗?因为我觉得它涵盖了所有场景,我只想知道为什么,在我添加最后return和生活的好之前

最后这个工作正常:

String getName(){
    for(;;){
        for(; i < limit; i++){// i is already defined
            if(someArrayList.get(i).isDead)
                continue;
            return someArrayList.get(i).name;
        }
        return "";
    }
}

Mr. skeet says this type of code is ok in java

4 个答案:

答案 0 :(得分:6)

您需要最终return声明,因为您的列表可能只包含“死亡”字样。条目,在这种情况下,您的计划将达到限制&#39;并退出for循环。

我在这里看到评论,因此需要澄清。编译器只是不能分析所有潜在的结果,并100%确定循环是否会达到其自然结束。理论上讲它是不可能的(你可以阅读The Halting Problem了解更多信息)。

虽然编译器可以解决有时,但通常只会尝试在相对简单的情况下执行此操作。其背后的原因很简单 - 如果你的代码足够复杂以至于不清楚循环是否结束 - 它会让一个不理解为什么会出现这种情况的人类读者感到困惑。循环后没有return语句。这样的代码是错误的代码。

答案 1 :(得分:2)

因为你可以摆脱循环。一般来说,你必须返回一些东西,这就是预期会发生的事情。编译器不是魔术师,不能说明你的循环条件是否无限(至少在大多数情况下),通常它是运行时相关的。

答案 2 :(得分:2)

NP Hard

简短版本,您要求计算机执行的操作不仅复杂或困难,而且非常难以为它提供NP Hard的特殊术语,并且在Stack Overflow上有相当好的覆盖率,请参阅'NP Hard vs NP Complete',或者此question about proving the halting problem is NP Hard或此question on Mathematics Stack Overflow,最后但并非最不重要的是Wikipedia for the general definition of NP Hard。编译器不信任条件块,并希望有一个返回语句的路径,该路径不依赖于该条件块。

图灵的诅咒

长版本,当编译器通过代码评估路径时,它会创建一个名为a lattice的结构来跟踪该方法的所有不同路径。在方法需要返回值的情况下,编译器通过从方法出口点开始使用晶格并检查所有向后路径以查找返回值。是的,你的循环有一个return语句,但是编译器不能事先知道你的条件块总是会退出,所以它在查找返回值时会忽略该块。

See the Halting Problem它实际上解决了您的一些示例,但请确保您查看this answer这是我最喜欢的仅仅是因为它的魅力。如果编译器要编译以查找那些特定的代码习语,那么你声称编译器应该能够告诉循环将退出的说法是有价值的。但这就是问题所在,如果尝试使用膨胀的编译器,则会有太多特殊情况要编写代码。因此,它概括了大小写,并在查找返回值的路径时忽略条件块。

解决方案

Jon Skeet所说的是在方法中有多个退出点是可以的,他没有说在条件块中只有一个退出点是可以的。

您有理由看到以下版本的代码,它提供了返回值的默认路径,这只是提供它的一种方法。

String getName(){

    // default return value
    String retVal = "";

    for(;i < limit; i++){// i is already defined
        if(someArrayList.get(i).isDead)
            continue;
        return someArrayList.get(i).name;
    }

    //needs a final return
    return retVal;
}

当您说下面的代码时,

  

将违反返回类型方法:它是无限的,但为什么会这样   代码需要最终的返回值吗?

String getName(){
    for(;;){}
}

我想指出代码需要通过在方法声明中定义返回值,因此以下内容不会导致编译错误

void getName(){
    for(;;){}
}

然后问题就会回到你面前,为什么你坚持声明一个方法必须返回一些东西,同时还坚持只使用由条件块限制的结构,这样编译器就无法检测到它们总是会执行。

问题

我向你提出的问题是你为什么不使用默认的返回值,是否有某种原因你似乎在避免这种方法?这对我来说并不重要,但它有助于了解你是否有像编码标准这样的实用挑战,或者它是否更像是一个哲学上的反对。

答案 3 :(得分:1)

在你致电i = 11之前

getName(),它永远不会进入循环,因此它需要return

修改

String getName(){
for(; i < 10; i++){// i is already defined
    if((i+1) == limit){
        if(!someArrayList.get(i).isDead)
            return "";

        // MISSING else STATEMENT HERE
        // If when i == 9 the execution reach this point, 
        // it will jump to ----(portal)
    }else{
        if(someArrayList.get(i).isDead)
            continue;  // ALSO HERE, if i == 9 it continues, and then it jumps to ----(portal)
        return someArrayList.get(i).name;
    }
}
// needs a final return

// (portal)----> here. Needs return statement
}