如何避免Java方法中无用的返回?

Oli*_*ing 115 java

我有一种情况,理论上总是会到达return嵌套在两个for循环中的语句.

编译器不同意并且需要returnfor循环之外的语句.我想知道一种优雅的方法来优化这种方法,这超出了我目前的理解,并且我尝试的中断实现似乎都不起作用.

Attached是一种来自赋值的方法,它生成随机整数并返回循环的迭代,直到找到第二个随机整数,在作为int参数传递给方法的范围内生成.

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    for (int count = 1; count <= range; count++) { // Run until return.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                return count;
            }
        }
    }
    return 0; // Never reached
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ica 343

编译器的启发式方法永远不会让你省略最后一个return.如果你确定它永远不会到达,我会用a替换它throw以使情况清楚.

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    for (int count = 1; count <= range; count++) {
        ...
    }

    throw new AssertionError("unreachable code reached");
}
Run Code Online (Sandbox Code Playgroud)

  • 不仅可读性,还要确保您发现代码是否有问题.发生器可能有一个错误是完全合理的. (133认同)
  • 也许应该是`抛出新的AssertionError("\"无法访问\"代码到达");` (21认同)
  • 我会在生产程序中写下我在答案中的确切内容. (7认同)
  • 如果您绝对确定您的代码永远无法访问"无法访问的代码",那么可以为可能出现的所有边缘情况创建一些单元测试(范围为0,范围为-1,范围为最小/最大int).它现在可能是一种私有方法,但下一个开发人员可能不会这样做.如何处理意外值(抛出异常,返回错误值,什么都不做)取决于您将如何使用该方法.根据我的经验,您通常只想记录错误并返回. (5认同)

l0b*_*0b0 36

正如@BoristheSpider所指出的,你可以确保第二个return语句在语义上不可达:

private static int oneRun(int range) {
    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    int count = 0;

    while (true) {
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                return count;
            }
        }
        count++;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译并运行良好.如果你得到一个,ArrayIndexOutOfBoundsException你就会知道实现在语义上是错误的,而不必明确地抛出任何东西.

  • @cmaster:你可以省略`true`:`for(int count = 0 ;; count ++)...` (3认同)
  • 我不想改为"for"."while-true"是一个明显的标志,预计该块将无条件地循环,除非并且直到某些内部破坏它.具有省略条件的"for"不能清楚地通信; 它可以更容易被忽视. (3认同)

Dav*_*ler 18

由于您询问了两个for循环的中断,您可以使用标签来执行此操作(请参阅下面的示例):

private static int oneRun(int range) {
    int returnValue=-1;

    int[] rInt = new int[range+1]; // Stores the past sequence of ints.
    rInt[0] = generator.nextInt(range); // Inital random number.

    OUTER: for (int count = 1; count <= range; count++) { // Run until return.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.   
        for (int i = 0; i < count; i++) { // Check for past occurence and return if found.
            if (rInt[i] == rInt[count]) {
                returnValue = count;
                break OUTER;
            }
        }
    }
    return returnValue;
}
Run Code Online (Sandbox Code Playgroud)

  • 标签是不是你最好避免的那种东西? (4认同)
  • 高( - )级编程语言中的标签.*绝对野蛮......* (4认同)
  • 我相信你在考虑搞砸. (2认同)

Sul*_*han 13

虽然断言是一个很好的快速解决方案.一般来说,这种问题意味着您的代码太复杂了.当我查看你的代码时,显然你并不真的想要一个数组来保存以前的数字.你想要一个Set:

Set<Integer> previous = new HashSet<Integer>();

int randomInt = generator.nextInt(range);
previous.add(randomInt);

for (int count = 1; count <= range; count++) {
    randomInt = generator.nextInt(range);
    if (previous.contains(randomInt)) {
       break;
    }

    previous.add(randomInt);
}

return previous.size();
Run Code Online (Sandbox Code Playgroud)

现在请注意,我们返回的内容实际上是集合的大小.代码复杂度从二次变为线性,并且立即更具可读性.

现在我们可以意识到我们甚至不需要那个count索引:

Set<Integer> previous = new HashSet<Integer>();

int randomInt = generator.nextInt(range);

while (!previous.contains(randomInt)) {          
    previous.add(randomInt);      
    randomInt = generator.nextInt(range);
}

return previous.size();
Run Code Online (Sandbox Code Playgroud)


a_g*_*est 8

由于您的返回值基于外部循环的变量,您可以简单地将外部循环的条件更改为count < range,然后在函数末尾返回最后一个值(您刚刚省略):

private static int oneRun(int range) {
    ...

    for (int count = 1; count < range; count++) {
        ...
    }
    return range;
}
Run Code Online (Sandbox Code Playgroud)

这样您就不需要引入永远无法访问的代码.


小智 5

使用临时变量,例如"result",并删除内部返回.使用适当的条件更改while循环的for循环.对我来说,只有一个返回作为函数的最后一个语句总是更优雅.

  • 一般来说,没有充分理由只能获得一次回报. (2认同)