我阅读了有关Lambda表达式的Java 8教程,并且不太了解"对特定类型的任意对象的实例方法的引用的方法参考示例"
在同一个教程中,有一个例子"参考特定对象的实例方法"看起来很喜欢。
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)接受两个参数并使用相同的两个参数调用方法。
现在"引用特定类型的任意对象的实例方法"示例使用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)我不明白编译器如何决定Arrays.sort第二个参数的可接受性。我想也许它足够聪明,可以理解如何调用该方法,所以我创建了一个例子。
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方法相同
答案 0 :(得分:6)
在FakeString
中,您的compareToIgnoreCase
有一个String
参数,因此无法取代Comparator<String>
,这需要一个带有两个String参数的方法
在FakeString2
中,您的compareToIgnoreCase
有一个隐含的FakeString
参数(this)和一个String参数,因此,它再次无法取代Comparator<String>
}。
答案 1 :(得分:6)
这是某个对象的方法引用与正在处理的对象的方法引用之间的区别。
首先是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[]
进行排序,因此在compareToIgnoreCase
实例上调用方法String
,当前正在使用其他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
上调用此方法。因此,我们必须在static
上调用FakeString
方法。但我们也不能这样做,因为我们需要一个方法(String, String) -> int
,但我们只有(String) -> int
- 编译错误。
在第二个示例中,问题完全相同,因为您仍然有String[]
。 compareToIgnoreCase
签名错误。
你遗漏的一点是String::compareToIgnoreCase
例子;该方法在当前正在处理的String
上调用。