【问题标题】:Java loops compile errorsJava 循环编译错误
【发布时间】:2015-09-28 09:48:39
【问题描述】:

谁能给我解释一下?首先,我知道为什么这段代码

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;
        }
    }
}

是因为它有一个范围吗?因为我觉得它涵盖了所有场景,所以我只想知道为什么,在我添加最后一个returnand life's good

最后这没问题:

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

【问题讨论】:

  • 如果i 最初已经超过limit(或10)怎么办?除非i 的值可以在编译时确定,否则您需要最终返回,因为循环可能永远 运行。并且编译器可能不会非常努力地确定i 的可能范围。
  • 我也将该代码更改为for(int i =0; i &lt; 10; i++) 仍然是那个错误,还有 10 是因为我想具体一点,但我的范围是用户可能选择的限制,在此之前我正在检查如果限制不是数组列表的大小。@dhke

标签: java loops


【解决方案1】:

您需要一个最终的return 语句,因为您的列表可能只包含“死”条目,在这种情况下,您的程序将达到“限制”并退出 for 循环。

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

虽然编译器有时可以弄清楚,但它通常只在相对简单的情况下尝试这样做。其背后的原因很简单——如果你的代码足够复杂以至于不清楚循环是否结束——它会让人类读者感到困惑,他们不会理解为什么循环之后没有 return 语句。这样的代码是坏代码。

【讨论】:

  • 更具体地说:Java 编译器不会尝试并尝试分析所有可能的状态排列。如果其有限的代码分析无法证明您的回报总是被执行,那么它别无选择,只能谨慎行事并拒绝您的代码。
  • @user268396 但它不会拒绝我没有得到的无限循环,如果您可以在返回方法中采用无限循环,为什么不允许复杂的返回循环?
  • 感谢您的回答 Mr.Zmbg,我明白了,那么为什么编译器允许在返回方法中无限循环?它是一样的还是?如果它愿意冒险,为什么不这样做呢?在一天结束时,我的程序将崩溃或 mul 函数而不是编译器或 jvm
  • 它不拒绝无限循环,当唯一的返回是在条件块内时,它不相信它们提供返回值,有关更多详细信息,请参阅我的答案。
  • 编译器不愿意冒险的事情,流分析涵盖了一些结构,但没有涵盖其他的。默认的 java 编译器似乎忽略了固定变量值,但它支持没有中断和停止条件的循环。如前所述,他的编译器并不能处理所有极端情况,只处理在流分析器中实现的情况。
【解决方案2】:

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

【讨论】:

  • 但是如果我在第四个示例中添加 break 而不是 return 它会导致相同的编译错误,即使它是无限循环
  • 嗯,你会期待什么? ;_;那么根本就没有return语句。
【解决方案3】:

如果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
}

【讨论】:

  • 即使for(int i =0; i &lt; 10;i++)他还在抱怨
【解决方案4】:

NP 困难

短版,你要求计算机做的不仅仅是复杂或困难,而是太难了,有一个特殊的术语 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(;;){}
}

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

问题

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

【讨论】:

  • hmmm 我想还有更多只是 for 循环,我需要时间来积累所有这些感谢 Mr.French,回来添加最后的回报,还有你的问题,不,我只是被带走了这种方法是因为起初我有一个 if else 代码,它是一个简单的是/否返回,并且从我从您的链接中完成的少量阅读中,它停止了,所以编译器对此没有问题,然后我跳入推送更多代码对它,它是优柔寡断的,猜它不是那么聪明):呵呵,这就是为什么我只是使用这种方法,谢谢,
  • 抱歉吹毛求疵,但这个停止问题不是 NP Hard。它甚至不在 R 中。
  • 这是 NP Hard,what it is not is NP Complete。我将添加更多关于此的链接,因为我不希望这一点分散 OP 的问题。
猜你喜欢
  • 1970-01-01
  • 2016-01-20
  • 2013-04-03
  • 2015-04-01
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多