Java 8 和方法引用 - 特别是 compareToIgnoreCase
Java 8 and method references - specifically compareToIgnoreCase
我阅读了有关 Lambda 表达式的 Java 8 教程,但不太理解 "Reference to an instance method of an arbitrary object of a particular type"
的方法参考示例
在同一教程中有一个示例 "Reference to an Instance Method of a Particular Object" 看起来很像。
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
我可以看到这个工作,因为方法 compareByName 具有与 Comparator.compare 相同的签名,lambda (a, b) -> myComparisonProvider.compareByName(a, b) 接受两个参数并调用一个方法具有相同的两个参数。
现在 "Reference to an instance method of an arbitrary object of a particular type" 示例使用 String::compareToIgnoreCase
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
该方法的签名是 int compareTo(String anotherString)
,与 Comparator.compare 不同。该教程不是很清楚,但似乎暗示您最终会得到一个 lambda,例如 (a, b) -> a.compareToIgnoreCase(b) 我不明白编译器如何决定 [= 的第二个参数可接受的参数35=] 我想也许理解如何调用该方法就足够聪明了,所以我创建了一个示例。
public class LambdaTest {
public static void main(String... args) {
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase); // This works
// using Static methods
Arrays.sort(stringArray, FakeString::compare); // This compiles
Arrays.sort(stringArray, FakeString::compareToIgnoreCase); // This does not
// using Instance methods
LambdaTest lt = new LambdaTest();
FakeString2 fs2 = lt.new FakeString2();
Arrays.sort(stringArray, fs2::compare); // This compiles
Arrays.sort(stringArray, fs2::compareToIgnoreCase); // This does not
for(String name : stringArray){
System.out.println(name);
}
}
static class FakeString {
public static int compareToIgnoreCase(String a) {
return 0;
}
public static int compare(String a, String b) {
return String.CASE_INSENSITIVE_ORDER.compare(a, b);
}
}
class FakeString2 implements Comparator<String> {
public int compareToIgnoreCase(String a) {
return 0;
}
@Override
public int compare(String a, String b) {
return String.CASE_INSENSITIVE_ORDER.compare(a, b);
}
}
}
有人可以解释为什么上面两个 Arrays.sort 即使使用与 String.compareToIgnoreCase 方法
相同的方法也不能编译吗
在 FakeString
中,您的 compareToIgnoreCase
有一个 String
参数,因此它不能代替 Comparator<String>
,它需要一个包含两个参数的方法字符串参数。
在 FakeString2
中,您的 compareToIgnoreCase
有一个隐含的 FakeString
参数 (this) 和一个 String 参数,因此,它不能代替 Comparator<String>
.
这是对某个对象的方法引用与对对象正在处理的方法引用之间的区别。
首先是Oracle实例
让我们看看第一个案例:
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
此处,方法 compareByName
在 myComparisonProvider
的传入实例上使用 sort
算法中的每对参数调用。
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = myComparisonProvider.compareByName(a,b);
现在,在第二种情况下:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
您正在对 String[]
进行排序,因此在当前正在排序的 String
实例上调用方法 compareToIgnoreCase
,并将另一个 String
作为参数。
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = a.compareToIgnoreCase(b);
所以这是两种不同的情况:
- 一个你在任意对象实例上传递一个方法;和
- 其中一个是您传入要在正在处理的实例上调用的方法。
你的例子
现在在您的第一个示例中,您还有一个 String[]
并尝试对其进行排序。所以:
Arrays.sort(stringArray, FakeString::compare);
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = FakeString.compare(a, b);
唯一的区别是 compare
是 static
。
Arrays.sort(stringArray, FakeString::compareToIgnoreCase);
现在,String[]
不是 FakeString[]
,所以我们不能在 String
上调用此方法。因此我们必须在 FakeString
上调用 static
方法。但是我们也不能这样做,因为我们需要一个方法 (String, String) -> int
但我们只有 (String) -> int
- 编译错误。
在第二个示例中,问题完全相同,因为您仍然有 String[]
。 compareToIgnoreCase
签名错误。
TL;DR:
你遗漏的一点是在 String::compareToIgnoreCase
例子中;该方法在 String
当前正在处理.
上调用
我阅读了有关 Lambda 表达式的 Java 8 教程,但不太理解 "Reference to an instance method of an arbitrary object of a particular type"
的方法参考示例在同一教程中有一个示例 "Reference to an Instance Method of a Particular Object" 看起来很像。
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
我可以看到这个工作,因为方法 compareByName 具有与 Comparator.compare 相同的签名,lambda (a, b) -> myComparisonProvider.compareByName(a, b) 接受两个参数并调用一个方法具有相同的两个参数。
现在 "Reference to an instance method of an arbitrary object of a particular type" 示例使用 String::compareToIgnoreCase
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
该方法的签名是 int compareTo(String anotherString)
,与 Comparator.compare 不同。该教程不是很清楚,但似乎暗示您最终会得到一个 lambda,例如 (a, b) -> a.compareToIgnoreCase(b) 我不明白编译器如何决定 [= 的第二个参数可接受的参数35=] 我想也许理解如何调用该方法就足够聪明了,所以我创建了一个示例。
public class LambdaTest {
public static void main(String... args) {
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase); // This works
// using Static methods
Arrays.sort(stringArray, FakeString::compare); // This compiles
Arrays.sort(stringArray, FakeString::compareToIgnoreCase); // This does not
// using Instance methods
LambdaTest lt = new LambdaTest();
FakeString2 fs2 = lt.new FakeString2();
Arrays.sort(stringArray, fs2::compare); // This compiles
Arrays.sort(stringArray, fs2::compareToIgnoreCase); // This does not
for(String name : stringArray){
System.out.println(name);
}
}
static class FakeString {
public static int compareToIgnoreCase(String a) {
return 0;
}
public static int compare(String a, String b) {
return String.CASE_INSENSITIVE_ORDER.compare(a, b);
}
}
class FakeString2 implements Comparator<String> {
public int compareToIgnoreCase(String a) {
return 0;
}
@Override
public int compare(String a, String b) {
return String.CASE_INSENSITIVE_ORDER.compare(a, b);
}
}
}
有人可以解释为什么上面两个 Arrays.sort 即使使用与 String.compareToIgnoreCase 方法
相同的方法也不能编译吗在 FakeString
中,您的 compareToIgnoreCase
有一个 String
参数,因此它不能代替 Comparator<String>
,它需要一个包含两个参数的方法字符串参数。
在 FakeString2
中,您的 compareToIgnoreCase
有一个隐含的 FakeString
参数 (this) 和一个 String 参数,因此,它不能代替 Comparator<String>
.
这是对某个对象的方法引用与对对象正在处理的方法引用之间的区别。
首先是Oracle实例
让我们看看第一个案例:
public int compareByName(Person a, Person b) {
return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
此处,方法 compareByName
在 myComparisonProvider
的传入实例上使用 sort
算法中的每对参数调用。
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = myComparisonProvider.compareByName(a,b);
现在,在第二种情况下:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
您正在对 String[]
进行排序,因此在当前正在排序的 String
实例上调用方法 compareToIgnoreCase
,并将另一个 String
作为参数。
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = a.compareToIgnoreCase(b);
所以这是两种不同的情况:
- 一个你在任意对象实例上传递一个方法;和
- 其中一个是您传入要在正在处理的实例上调用的方法。
你的例子
现在在您的第一个示例中,您还有一个 String[]
并尝试对其进行排序。所以:
Arrays.sort(stringArray, FakeString::compare);
所以在这里,当比较a
和b
时,我们实际上调用了:
final int c = FakeString.compare(a, b);
唯一的区别是 compare
是 static
。
Arrays.sort(stringArray, FakeString::compareToIgnoreCase);
现在,String[]
不是 FakeString[]
,所以我们不能在 String
上调用此方法。因此我们必须在 FakeString
上调用 static
方法。但是我们也不能这样做,因为我们需要一个方法 (String, String) -> int
但我们只有 (String) -> int
- 编译错误。
在第二个示例中,问题完全相同,因为您仍然有 String[]
。 compareToIgnoreCase
签名错误。
TL;DR:
你遗漏的一点是在 String::compareToIgnoreCase
例子中;该方法在 String
当前正在处理.