在Java中管理高度重复的代码和文档

在Java中管理高度重复的代码和文档,java,maintenance,guava,preprocessor,Java,Maintenance,Guava,Preprocessor,高度重复的代码通常是一件坏事,有一些设计模式可以帮助最小化这一点。然而,由于语言本身的限制,有时这是不可避免的。以java.util.Arrays中的以下示例为例: /** * Assigns the specified long value to each element of the specified * range of the specified array of longs. The range to be filled * extends from index <tt

高度重复的代码通常是一件坏事,有一些设计模式可以帮助最小化这一点。然而,由于语言本身的限制,有时这是不可避免的。以
java.util.Arrays
中的以下示例为例:

/**
 * Assigns the specified long value to each element of the specified
 * range of the specified array of longs.  The range to be filled
 * extends from index <tt>fromIndex</tt>, inclusive, to index
 * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
 * range to be filled is empty.)
 *
 * @param a the array to be filled
 * @param fromIndex the index of the first element (inclusive) to be
 *        filled with the specified value
 * @param toIndex the index of the last element (exclusive) to be
 *        filled with the specified value
 * @param val the value to be stored in all elements of the array
 * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
 * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
 *         <tt>toIndex &gt; a.length</tt>
 */
public static void fill(long[] a, int fromIndex, int toIndex, long val) {
    rangeCheck(a.length, fromIndex, toIndex);
    for (int i=fromIndex; i<toIndex; i++)
        a[i] = val;
}
上述行在源代码中出现了11次

因此,我的问题是:

  • 这些重复的Java代码/文档在实践中是如何处理的?它们是如何开发、维护和测试的?
    • 你是从“原稿”开始,让它尽可能成熟,然后根据需要复制和粘贴,希望你没有犯错误吗
    • 如果您在原始版本中确实犯了错误,那么只需到处修复它,除非您习惯于删除副本并重复整个复制过程
    • 您对测试代码也应用了相同的过程吗
  • 对于这类事情,Java会从某种有限使用的源代码预处理中受益吗?
    • 也许Sun有自己的预处理器来帮助编写、维护、记录和测试这些重复的库代码

一条评论要求另一个例子,所以我从谷歌收藏中提取了这个例子:第276-310行(
AndPredicate
)和第312-346行(
OrPredicate

这两个类的源是相同的,除了:

  • AndPredicate
    vs
    或predicate
    (每个在其类中出现5次)
  • ”和(“
    vs
    或(“
    ”(在相应的
    toString()
    方法中)
  • #和
    vs
    #或
    (在
    中,请参见
    Javadoc注释)
  • true
    vs
    false
    (在
    apply
    中;
    可以从表达式中重写)
  • -1/*所有位打开*/
    0/*所有位关闭*/
    中的
    hashCode()
  • &=
    vs
    |=
    中的
    hashCode()

由于泛型,现在可以避免大量此类重复。在编写只有类型更改的相同代码时,泛型是天赐良机


遗憾的是,我认为泛型数组仍然没有得到很好的支持。至少现在,使用允许您利用泛型的容器。多态性也是减少此类代码重复的有用工具


要回答您关于如何处理绝对必须复制的代码的问题,请使用易于搜索的注释标记每个实例。有一些java预处理器添加了C风格的宏。我想我记得netbeans有一个。如果您绝对必须复制代码,请遵循您给出的伟大示例并对所有实例进行分组在一个地方,当你必须进行更改时,很容易找到并修复这些代码。记录复制,更重要的是,记录复制的原因,以便在你之后的每个人都知道这两者。

来源:不要重复你自己(干)或复制是邪恶的(死)

在某些情况下,实施DRY理念所需的努力可能大于维护数据的单独副本所需的努力。在某些其他情况下,重复的信息是不可变的,或者受到足够严格的控制,因此不需要DRY


可能没有答案或技术来防止类似的问题。

我知道Sun必须为Java SE库代码编写这样的文档,也许其他第三方库作者也会这样做


然而,我认为在这样一个文件中复制和粘贴文档是一种完全的浪费,因为这样的代码只在内部使用。我知道很多人会不同意,因为这会使他们的内部Javadoc看起来不那么干净。然而,取舍是使他们的代码更干净,在我看来,这更重要。

JavaP基本类型让你很讨厌,尤其是在数组方面。如果你特别询问涉及基本类型的代码,那么我会说尽量避免使用它们。如果你使用装箱类型,Object[]方法就足够了


一般来说,你需要进行大量的单元测试,除了诉诸反射之外,真的没有其他事情可以做。正如你所说,这完全是另一个主题,但不要太害怕反射。首先编写尽可能枯燥的代码,然后分析它,并确定反射性能是否真的足够差,足以保证wri清理和维护额外的代码。

您可以使用代码生成器使用模板来构造代码的变体。在这种情况下,java源代码是生成器的产品,真正的代码是模板。

对于绝对需要性能的人来说,装箱和拆箱以及泛化集合等等都是大禁忌o's

同样的问题也发生在性能计算中,在性能计算中,您需要相同的复杂度来处理float和double(比如goldbergd的“论文”中显示的一些方法)

在处理类似数量的数据时,
TIntIntHashMap
围绕Java的
HashMap
运行循环是有原因的

现在,Trove集合的源代码是如何编写的

当然,通过使用源代码插装:)

有几个Java库可以获得更高的性能(比默认的Java库高得多),它们使用代码生成器来创建重复的源代码

我们都知道“源代码插装”是邪恶的,代码生成是垃圾,但真正知道自己在做什么的人(即编写Trove之类的东西的人)就是这样做的:)

值得一提的是,我们生成的源代码包含以下大警告:

/*
 * This .java source file has been auto-generated from the template xxxxx
 * 
 * DO NOT MODIFY THIS FILE FOR IT SHALL GET OVERWRITTEN
 * 
 */

给定两个声称相似的代码片段,大多数语言在构造将代码片段统一为一个整体的抽象方面的功能有限
/*
 * This .java source file has been auto-generated from the template xxxxx
 * 
 * DO NOT MODIFY THIS FILE FOR IT SHALL GET OVERWRITTEN
 * 
 */