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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42184317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 06:25:41  来源:igfitidea点击:

How do I avoid a useless return in a Java method?

java

提问by Oliver Benning

I have a situation where the returnstatement nested in two forloops will always be reached, theoretically.

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

The compiler disagrees and requires a returnstatement outside of the forloop. I'd like to know an elegant way to optimize this method that's beyond my current understanding, and none of my attempted implementations of break seem to work.

编译器不同意并需要循环return外的语句for。我想知道一种优化此方法的优雅方式,这超出了我目前的理解,而且我尝试的 break 实现似乎都不起作用。

Attached is a method from an assignment that generates random integers and returns the iterations cycled through until a second random integer is found, generated within a range passed into the method as an int parameter.

附加的是来自赋值的方法,该方法生成随机整数并返回循环的迭代,直到找到第二个随机整数,在作为 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
}

回答by John Kugelman

The compiler's heuristics will never let you omit the last return. If you're sure it'll never be reached, I'd replace it with a throwto make the situation clear.

编译器的启发式永远不会让您省略最后一个return. 如果您确定永远不会到达它,我会将其替换为 athrow以使情况清楚。

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

回答by l0b0

As @BoristheSpider pointed outyou can make sure the second returnstatement is semantically unreachable:

正如@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++;
    }
}

Compiles & runs fine. And if you ever get an ArrayIndexOutOfBoundsExceptionyou'll know the implementation was semantically wrong, without having to explicitly throw anything.

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

回答by David Choweller

Since you asked about breaking out of two forloops, you can use a label to do that (see the example below):

既然你问的是打破两个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;
}

回答by Sulthan

While an assert is a good fast solution. In general this kind of problems means that your code is too complicated. When I am looking at your code, it's obvious that you don't really want an array to hold previous numbers. You want a Set:

虽然断言是一个很好的快速解决方案。一般来说,这类问题意味着你的代码太复杂了。当我查看您的代码时,很明显您并不真正想要一个数组来保存以前的数字。你想要一个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();

Now note that what we are returning is actually the size of the set. The code complexity has decreased from quadratic to linear and it is immediately more readable.

现在请注意,我们返回的实际上是集合的大小。代码复杂度从二次型降低到线性型,可读性立即提高。

Now we can realize that we don't even need that countindex:

现在我们可以意识到我们甚至不需要那个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();

回答by a_guest

As your return value is based on the outer loop's variable you could simply alter the outer loop's condition to count < rangeand then return this last value (which you've just omitted) at the end of the function:

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

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

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

This way you don't need to introduce code that will never be reached.

这样您就不需要引入永远不会到达的代码。

回答by David

Use a temp variable, for instance "result" , and remove the inner return. Change the for loop for a while loop with the proper condition. To me it's always more elegant to have only one return as the last statement of the function.

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

回答by Lachezar

Methods that have a return statement and have a loop/loops inside them always require a return statement outside the loop(s). Even if this statement outside the loop is never reached. In such cases, in order to avoid unnecessary return statements, you could define a variable of the respective type, an integer in your case, at the beginning of the method i.e. before and outside the respective loop(s). When the desired result inside the loop is reached, you can ascribe the respective value to this pre-defined variable and use it for the return statement outside the loop.

具有 return 语句并在其中具有循环/循环的方法总是需要循环外的 return 语句。即使永远不会到达循环外的这个语句。在这种情况下,为了避免不必要的 return 语句,您可以在方法的开头(即在相应循环之前和之外)定义相应类型的变量,在您的情况下是整数。当达到循环内所需的结果时,您可以将相应的值归因于该预定义变量,并将其用于循环外的 return 语句。

Since you want your method to return the first result when rInt[i] equals rInt[count], implementing only the above-mentioned variable is not enough because the method will return the last result when rInt[i] equals rInt[count]. One options is to implement two "break statements" that are called when the we have the desired result. So, the method will look something like this:

由于您希望您的方法在 rInt[i] 等于 rInt[count] 时返回第一个结果,仅实现上述变量是不够的,因为该方法将在 rInt[i] 等于 rInt[count] 时返回最后一个结果。一种选择是实现两个“break 语句”,当我们得到所需的结果时调用它们。因此,该方法将如下所示:

private static int oneRun(int range) {

        int finalResult = 0; // the above-mentioned variable
        int[] rInt = new int[range + 1];
        rInt[0] = generator.nextInt(range);

        for (int count = 1; count <= range; count++) {
            rInt[count] = generator.nextInt(range);
            for (int i = 0; i < count; i++) {
                if (rInt[i] == rInt[count]) {
                    finalResult = count;
                    break; // this breaks the inside loop
                }
            }
            if (finalResult == count) {
                break; // this breaks the outside loop
            }
        }
        return finalResult;
    }

回答by Robert Hanson

Maybe this is an indication that you should rewrite your code. For example:

也许这表明您应该重写代码。例如:

  1. Create an array of integers 0 .. range-1. Set all the values to 0.
  2. Perform a loop. In the loop, generate a random number. Look in your list, at that index, to see if the value is 1 If it is, break out of the loop. Otherwise, set the value at that index to 1
  3. Count the number of 1s in the list, and return that value.
  1. 创建一个整数数组 0 .. range-1。将所有值设置为 0。
  2. 执行一个循环。在循环中,生成一个随机数。在您的列表中查看该索引处的值是否为 1 如果是,则跳出循环。否则,将该索引处的值设置为 1
  3. 计算列表中 1 的数量,并返回该值。

回答by Sergey Fedorov

I agree that one should throw an exception where unreachable statement occurs. Just wanted to show how the same method can do this in more readable way (java 8 streams required).

我同意应该在发生无法访问的语句时抛出异常。只是想展示相同的方法如何以更易读的方式执行此操作(需要 java 8 流)。

private static int oneRun(int range) {
    int[] rInt = new int[range + 1];
    return IntStream
        .rangeClosed(0, range)
        .peek(i -> rInt[i] = generator.nextInt(range))
        .filter(i -> IntStream.range(0, i).anyMatch(j -> rInt[i] == rInt[j]))
        .findFirst()
        .orElseThrow(() -> new RuntimeException("Shouldn't be reached!"));
}

回答by blabla

private static int oneRun(int range) {
    int result = -1; // use this to store your result
    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 && result == -1; count++) { // Run until result found.
        rInt[count] = generator.nextInt(range); // Add randint to current iteration.   
        for (int i = 0; i < count && result == -1; i++) { // Check for past occurence and leave after result found.
            if (rInt[i] == rInt[count]) {
                result = count;
            }
        }
    }
    return result; // return your result
}