1. 概述
在这个教程中,我们将了解Arrays
类中的mismatch()
方法的行为。这个方法有三个主要重载版本,适用于不同类型的数组。我们将以int
数组为例进行讲解。
2. 基础mismatch()
方法
2.1. 共同前缀的长度
mismatch()
方法接受两个数组,并返回它们之间第一个不同的元素的索引。例如,{1, 2, 3, 4, 5}
和{1, 2, 3, 5, 8}
在索引3处不同。
让我们使用JUnit5编写一个单元测试来验证方法是否按预期工作:
@Test
void givenTwoArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() {
int[] firstArray = {1, 2, 3, 4, 5};
int[] secondArray = {1, 2, 3, 5, 8};
assertEquals(3, Arrays.mismatch(firstArray, secondArray));
}
我们可以注意到,如果一个数组是另一个数组的前缀,结果将是较短数组的长度:
@Test
void givenFirstArrayIsAPrefixOfTheSecond_whenMismatch_thenFirstArrayLength() {
int[] firstArray = {1, 2, 3, 4, 5};
int[] secondArray = {1, 2, 3, 4, 5, 6, 7, 8, 9};
assertEquals(firstArray.length, Arrays.mismatch(firstArray, secondArray));
}
如果两个数组的第一个元素不同,结果为0:
@Test
void givenNoCommonPrefix_whenMismatch_thenZero() {
int[] firstArray = {1, 2, 3, 4, 5};
int[] secondArray = {9, 8, 7};
assertEquals(0, Arrays.mismatch(firstArray, secondArray));
}
2.2. 边界情况
当两个数组具有相同的元素且顺序相同时,方法返回-1:
@Test
void givenTwoEmptyArrays_whenMismatch_thenMinusOne() {
assertEquals(-1, Arrays.mismatch(new int[] {}, new int[] {}));
}
请注意,两个空数组没有差异,因此在这种情况下结果也是-1:
@Test
void givenTwoEmptyArrays_whenMismatch_thenMinusOne() {
assertEquals(-1, Arrays.mismatch(new int[] {}, new int[] {}));
}
2.3. 空或空数组
然而,如果两个数组中恰好有一个为空,mismatch()
方法将返回空数组的长度,即0:
@Test
void givenExactlyOneAnEmptyArray_whenMismatch_thenZero() {
int[] firstArray = {};
int[] secondArray = {1, 2, 3};
assertEquals(0, Arrays.mismatch(firstArray, secondArray));
}
最后但同样重要的是,如果任何一个数组为null
,mismatch()
方法会抛出NullPointerException
:
@Test
void givenAtLeastANullArray_whenMismatch_thenThrowsNullPointerException() {
int[] firstArray = null;
int[] secondArray = {1, 2, 3, 4, 5};
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray));
}
此外,我们还可以将mismatch()
方法应用于boolean
、byte
、char
、short
、int
、long
、float
、double
和Object
数组。
3. 使用子数组的mismatch()
方法
接下来,我们将关注一个签名在int
数组中的方法变体:int mismatch(int[] a, int aFromIndex, int aToIndex, int[] b, int bFromIndex, int bToIndex)
。这个方法版本会从每个数组中提取子数组,然后检查差异。
3.1. 子数组的相似行为
让我们通过一个例子来看它的行为:
@Test
void givenTwoSubArraysWithACommonPrefix_whenMismatch_thenIndexOfFirstMismatch() {
int[] firstArray = {1, 2, 3, 4, 5};
int[] secondArray = {0, 1, 2, 3, 5, 8};
assertEquals(3, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 6));
}
逐步理解发生了什么:
- 首先,方法计算原始第一个数组
{1, 2, 3, 4, 5}
从索引0到4的子数组:结果是新数组{1, 2, 3, 4}
- 然后,它计算原始第二个数组
{0, 1, 2, 3, 5, 8}
从索引1到6的子数组:结果是数组{1, 2, 3, 5, 8}
- 最后,它对两个子数组应用基础的
mismatch()
方法:{1, 2, 3, 4}
和{1, 2, 3, 5, 8}
;两者都以{1, 2, 3}
的顺序开始,但在第四个元素处存在差异
因此,在这种情况下,方法返回4。与基础版本相同,所有点都适用于这些变体:
- 如果没有差异,方法返回-1
- 如果任何数组为
null
,方法会抛出NullPointerException
- 这个方法也适用于
boolean
、byte
、char
、short
、int
、long
、float
、double
和Object
数组
3.2. 其他异常
除了标准行为外,子数组方法还会引入新的异常。如果对于任意数组,"from"索引大于"to"索引,mismatch()
方法会抛出IllegalArgumentException
:
@Test
void givenToIndexGreaterThanFromIndex_whenMismatch_thenThrowsIllegalArgumentException() {
int[] firstArray = {2, 3, 4, 5, 4, 3, 2};
int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assertThrows(IllegalArgumentException.class, () -> Arrays.mismatch(firstArray, 4, 2, secondArray, 0, 6));
}
此外,如果我们传递非法索引作为参数,方法会抛出ArrayIndexOutOfBoundsException
:
@Test
void givenIllegalIndexes_whenMismatch_thenThrowsArrayIndexOutOfBoundsException() {
int[] firstArray = {2, 3, 4, 5, 4, 3, 2};
int[] secondArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assertThrows(ArrayIndexOutOfBoundsException.class, () -> Arrays.mismatch(firstArray, -1, 2, secondArray, 0, 6));
}
总之,"from"索引必须大于0,而"to"索引必须大于"from"索引且小于数组的长度。
4. 使用比较器的泛型方法
最后一个方法版本接受两个泛型类型的数组,并根据一个Comparator
计算第一个不匹配项。例如,我们可以拿两个String
数组并使用String
类的CASE_INSENSITIVE_ORDER
比较器:
@Test
void givenTwoStringArraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() {
String[] firstArray = {"one", "two", "three"};
String[] secondArray = {"ONE", "TWO", "FOUR"};
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
assertEquals(2, Arrays.mismatch(firstArray, secondArray, comparator));
}
关于边界情况和异常的所有先前章节中的点仍然适用。此外,如果提供的Comparator
为null
,也会抛出NullPointerException
:
@Test
void givenAtLeastANullArrayOrNullComparator_whenMismatch_thenThrowsNullPointerException() {
String[] firstArray = {"one"};
String[] secondArray = {"one"};
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
assertThrows(NullPointerException.class, () -> Arrays.mismatch(firstArray, secondArray, null));
}
最后,我们还可以注意到,有一个类似的子数组方法重写:
@Test
void givenTwoStringSubarraysAndAComparator_whenMismatch_thenIndexOfFirstMismatch() {
String[] firstArray = {"one", "two", "three", "four"};
String[] secondArray = {"ZERO", "ONE", "TWO", "FOUR", "EIGHT", "SIXTEEN"};
Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
assertEquals(2, Arrays.mismatch(firstArray, 0, 4, secondArray, 1, 3, comparator));
}
5. 总结
在这篇文章中,我们计算了两个数组之间的第一个不匹配。Java 9为此引入了mismatch()
方法。我们看到这个方法在很多情况下非常方便,因为它提供了大量的重写选项。
如往常一样,代码可以在GitHub上找到。