高度重复的代码通常是一件坏事,有一些设计模式可以帮助最小化这种情况。然而,有时由于语言本身的限制,这是不可避免的。以 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 > toIndex</tt>
* @throws ArrayIndexOutOfBoundsException if <tt>fromIndex < 0</tt> or
* <tt>toIndex > 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;
}
上面的代码片段在源代码中出现了8次,除了 完全相同的方法体之外,文档/方法签名几乎没有变化,对于根数组类型 int[]
、 short[]
、 char[]
、 byte[]
、 boolean[]
、 double[]
、 float[]
和 Object[]
各出现一次。
我相信,除非一个人诉诸于反思(这是一个完全不同的主题本身) ,这种重复是不可避免的。我理解作为一个实用程序类,如此高度集中的重复 Java 代码是非常不典型的,但是即使使用最佳实践 重复确实会发生!重构并不总是有效的,因为它并不总是可行的(显而易见的情况是当重复出现在文档中时)。
显然,维护这个源代码是一场噩梦。文档中的一个轻微输入错误,或者实现中的一个小错误,都会乘以重复的次数。事实上,最好的例子恰好涉及到这个类:
谷歌研究博客-额外,额外-阅读所有关于它: 几乎所有的二进制搜索和合并排序被破坏(由 Joshua Bloch,软件工程师)
这个错误非常微妙,很多人认为它只是一个简单明了的算法。
// int mid =(low + high) / 2; // the bug
int mid = (low + high) >>> 1; // the fix
以上线路 在源代码中出现11次!
所以我的问题是:
一个注释请求另一个例子,所以我从 Google Collection 中提取了这个例子: Com.google.common.base行276-310(AndPredicate
) vs 行312-346(OrPredicate
)。
这两个类的来源是相同的,除了:
AndPredicate
对 OrPredicate
(每个类出现5次)"And("
与 Or("
(在各自的 toString()
方法中)#and
与 #or
(在 @see
Javadoc 注释中)true
vs false
(在 apply
中; !
可以从表达式中重写)hashCode()
中的 -1 /* all bits on */
与 0 /* all bits off */
hashCode()
中的 &=
与 |=