java-逻辑内部循环?还是两个独立的几乎完全相同的循环?

注意:我的印象是您要避免循环内的逻辑语句.我之所以这么说是部分原因是因为编译器如何优化迭代可预测的任何循环.虽然我几乎可以肯定,但我早已听说过这一点,并且很长一段时间以来,我都将其视为惯例.可悲的是我找不到任何好的参考资料.但是,如果这是真的,则由于“ DRY”原理而导致一些冲突的情况(不要重复自己).

前提:假设您有相当大的数据集,请像我在本示例中使用的那样说一个多维数组.此外,假设您需要遍历每个条目并对所有或某些元素执行某些操作,并且需要能够选择要执行一项或另一项操作.这要求创建两个方法,其中90%-99%的代码在两者之间是相同的,而仅运算符或方法调用是不同的.如果这是C语言,我希望提供一个指向循环函数的函数指针,尽管我不知道是否也希望避免这种情况.

问题:使用逻辑语句并仅具有一个循环或两个几乎完全相同的方法会是更可取的吗?

示例:我提供了一些示例来展示“ twin”方法解决方案看起来有多冗余:

// This method is provided for completeness of the example
// and to provide some clue as to what boolean parameter and logic statement 
// I could alternatively have implemented within the loop method instead of external to it.
public int[][] addOrSubtractArrays(int[][] a, int[][] b, boolean useAdd){
    if(a == null || b == null || a.length != b.length || a.length < 1 || a[0].length != b.length)
        return null;
    return useAdd ? add(a, b) : subtract(a, b);
}

private int[][] add(int[][] a, int[][] b){
    int h = a.length;
    int w = a[0].length;
    int[][] c = new int[h][w];
    for(int y = 0; y < h; y++){
        for(int x = 0; x < w; x++){
            c[y][x] = a[y][x] + b[y][x];
        }
    }
    return c;
}

private int[][] subtract(int[][] a, int[][] b){
    int h = a.length;
    int w = a[0].length;
    int[][] c = new int[h][w];
    for(int y = 0; y < h; y++){
        for(int x = 0; x < w; x++){
            c[y][x] = a[y][x] - b[y][x];
        }
    }
    return c;
}

示例2 :(显而易见的?)替代方法

private int[][] addOrSubtract(int[][] a, int[][] b, boolean useAdd){
    if(a == null || b == null || a.length != b.length || a.length < 1 || a[0].length != b.length)
        return null;
    int h = a.length;
    int w = a[0].length;
    int[][] c = new int[h][w];
    for(int y = 0; y < h; y++){
        for(int x = 0; x < w; x++){
            if(useAdd)
                c[y][x] = a[y][x] + b[y][x];
            else
                c[y][x] = a[y][x] - b[y][x];
        }
    }
    return c;
}

我过于想采用某种通用方法来保持整个循环结构,以避免(几乎)重复代码.但是,如果“我所听到的”具有合理的上下文,就我所知,最好避免这种情况.

解决方法:

addOrSubtract不好.其他算术形式(例如乘法)又如何呢?您可以公开一个multipleOrDivide,但是如果应该选择addOrMultiply的时候到了怎么办?伸缩性不好.

您应该拥有的是一种方法,该方法允许客户端指定要执行的操作:

public int[][] calculate(int[][] first, int[][] second, Operation operation) {
    if(firstArray == null || secondArray == null || firstArray.length != secondArray.length || firstArray.length < 1 || firstArray[0].length != secondArray.length)
        throw new IllegalArgumentException("Arrays can't be null and must be of equal length.");

    int height = firstArray.length;
    int width = firstArray[0].length;
    int[][] result = new int[height][width];
    for(int y = 0; y < height; y++){
        for(int x = 0; x < width; x++){
            result[y][x] = operation.performOn(firstArray[y][x], secondArray[y][x]);
        }
    }
}

现在,您可以根据需要添加新的操作:

enum Operation {
    ADD {
        @Override
        public void performOn(int firstValue, int secondValue) {
            return firstValue + secondValue;
        }
    },
    SUBTRACT {
        //...
    };

    public abstract int performOn(int firstValue, int secondValue);
}

如果您觉得以这种方式进行覆盖会使扩展变得过于冗长,则可以通过将逻辑委托给回调函数来使用策略模式:

enum Operation { //could/should implement IOperation
    ADD((a, b) -> a + b),
    SUBTRACT((a, b) -> a - b);

    private IOperation operation;

    Operation(IOperation operation) {
        this.operation = operation;
    }

    public final int performOn(int firstValue, int secondValue) {
        return operation.performOn(firstValue, secondValue);
    }
}

interface IOperation {
    int performOn(int firstValue, int secondValue);
}

客户端现在可以使用您的功能,如下所示:

calculate(firstArray, secondArray, Operation.ADD);

我选择创建新的功能接口而不是使用BiFunction的原因是为了避免自动装箱.性能似乎是您的后顾之忧,而自动装箱会极大地影响性能,特别是如果您将强烈地执行此操作.无论是来自大型数组,还是需要在短时间内连续调用addOrSubtract,都最好避免陷阱.

IllegalArgumentException允许程序用描述性消息“炸毁”.您返回了null,这意味着使用此方法的任何人都需要执行null检查(有些杂物,代码气味,billion dollar mistake),否则他们可能会遇到没有描述性消息的NullPointerException.

上一篇:javascript-有没有一种方法可以按特定顺序从数组中构建字符串?


下一篇:遍历数组以在python中查找欧几里得距离