gpt4 book ai didi

java - 将 Java 数组和基元 (double[][]) 重构为集合和泛型 (List>)

转载 作者:搜寻专家 更新时间:2023-10-31 08:14:28 25 4
gpt4 key购买 nike

我一直在重构我几年前以类似 FORTRAN 的风格编写的一次性代码。大多数代码现在更有组织性和可读性。然而,该算法的核心(对性能至关重要)使用一维和二维 Java 数组,其典型代表是:

    for (int j = 1; j < len[1]+1; j++) {
int jj = (cont == BY_TYPE) ? seq[1][j-1] : j-1;
for (int i = 1; i < len[0]+1; i++) {
matrix[i][j] = matrix[i-1][j] + gap;
double m = matrix[i][j-1] + gap;
if (m > matrix[i][j]) {
matrix[i][j] = m;
pointers[i][j] = UP;
}
//...
}
}

为了清晰、可维护性和与其余代码的接口(interface),我想重构它。然而在阅读Java Generics Syntax for arraysJava Generics and number s 我有以下问题:

  • 性能。该代码计划使用大约 10^8 - 10^9 秒/年,这几乎是可管理的。我的阅读表明,将 double 更改为 Double 有时可以将性能提高 3 倍。我想要其他经验。我还希望从 foo[] 转移到 List 也会很成功。我没有第一手知识,再次经验会很有用。

  • 数组绑定(bind)检查。这在 double[] 和 List 中有不同的处理方式吗?这有关系吗?我预计有些问题会越界,因为该算法相当简单并且只应用于少数数据集。

  • 如果我不进行重构,那么代码就会混合使用这两种方法,造成丑陋且可能很脆弱。我已经在尝试编写诸如以下内容:

    列表 和列表 []

并了解删除并不能使它变得漂亮,充其量只会引起编译器警告。如果没有非常复杂的结构,似乎很难做到这一点。

  • 过时。一位发帖者建议应该废弃 Java 数组。我认为 RSN 不会发生这种情况,但我想摆脱过时的方法。

SUMMARY 目前的共识:

  • 与原始数组相比,集合具有显着的性能下降,尤其是对于矩阵等构造。这是在自动(取消)装箱数字和访问列表项时发生的

  • 对于严格的数值(科学)算法,数组符号 [][] 实际上更易于阅读,但变量的命名应尽可能有帮助

  • 泛型和数组不能很好地结合。将数组包装在类中以将它们传输进/出紧密算法可能很有用。

做出改变的客观原因很少

问题 @SeanOwen 建议将常量值从循环中取出会很有用。假设我没有搞砸这看起来像:

 int len1 = len[1];
int len0 = len[0];
int seq1 = seq[1];
int[] pointersi;
double[] matrixi;
for (int i = 1; i < len0+1; i++) {
matrixi = matrix[i];
pointersi = pointers[i];
}
for (int j = 1; j < len1+1; j++) {
int jj = (cont == BY_TYPE) ? seq1[j-1] : j-1;
for (int i = 1; i < len0+1; i++) {
matrixi[j] = matrixi[j] + gap;
double m = matrixi[j-1] + gap;
if (m > matrixi[j]) {
matrixi[j] = m;
pointersi[j] = UP;
}
//...
}
}

我认为编译器应该很聪明地做这类事情。我们还需要这样做吗?

最佳答案

我读了 Kent Beck 写的一本关于编码最佳实践的好书 (http://www.amazon.com/Implementation-Patterns/dp/B000XPRRVM)。还有一些有趣的性能数据。具体来说,数组和各种集合之间有比较,数组确实快得多(与 ArrayList 相比可能是 x3)。

此外,如果您使用 Double 而不是 double,则需要坚持使用,不要使用 double,因为自动(取消)装箱会降低您的表现。

考虑到您的性能需求,我会坚持使用基本类型数组


更重要的是,对于循环中的条件,我会只计算一次上限。这通常在循环之前的行中完成。

但是,如果您不喜欢仅在循环中使用的上限变量可在循环外访问,您可以像这样利用 for 循环的初始化阶段:

    for (int i=0, max=list.size(); i<max; i++) {
// do something
}

我不相信 Java 中的数组会过时。对于性能关键循环,我看不到任何语言设计者取消最快的选择(尤其是当差异是 x3 时)。


我理解您对可维护性以及与应用程序其余部分的一致性的关注。但我相信关键循环有权进行一些特殊实践。

我会尝试在不更改代码的情况下使代码尽可能清晰:

  • 通过仔细询问每个变量名称,最好与我的同事进行 10 分钟的头脑 Storm session
  • 通过编写编码注释(我一般反对使用它们,因为不清晰的代码应该弄清楚,而不是注释;但关键循环证明它是合理的)。
  • 根据需要使用私有(private)方法(正如 Andreas_D 在他的回答中指出的那样)。如造private final ,它们在运行时内联的可能性非常大(因为它们很短),因此在运行时不会对性能产生影响。

关于java - 将 Java 数组和基元 (double[][]) 重构为集合和泛型 (List<List<Double>>),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1409432/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com