简体   繁体   English

Java 8和方法引用 - 特别是compareToIgnoreCase

[英]Java 8 and method references - specifically compareToIgnoreCase

I read the Java 8 tutorial on Lambda Expressions and do not quite understand the Method Reference example for "Reference to an instance method of an arbitrary object of a particular type" 我阅读了有关Lambda表达式的Java 8教程,并且不太了解“引用特定类型的任意对象的实例方法”的方法参考示例

In the same tutorial there is an example "Reference to an Instance Method of a Particular Object" which look likes. 在同一个教程中,有一个示例“引用特定对象的实例方法”看起来很喜欢。

public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

I can see this working because the method compareByName has the same signature as Comparator.compare, lambda (a, b) -> myComparisonProvider.compareByName(a, b) takes two arguments and calls a method with the same two arguments. 我可以看到这个有效,因为方法compareByName与Comparator.compare具有相同的签名,lambda(a,b) - > myComparisonProvider.compareByName(a,b)接受两个参数并调用具有相同两个参数的方法。

Now the "Reference to an instance method of an arbitrary object of a particular type" example uses String::compareToIgnoreCase 现在,“引用特定类型的任意对象的实例方法”示例使用String :: compareToIgnoreCase

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

The signature for that method is int compareTo(String anotherString) and is different than Comparator.compare. 该方法的签名是int compareTo(String anotherString) ,与Comparator.compare不同。 The tutorial is not very clear but seem to imply you end up with a lambda such as (a, b) -> a.compareToIgnoreCase(b) I dont understand how the compiler decides what is acceptable for the second param of Arrays.sort I thought maybe it is smart enough to understand how to call that method, so I created an example. 教程不是很清楚,但似乎暗示你最终得到一个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);
        }
   }
}

Can some one explain why the above two Arrays.sort don't compile even though they are using methods that are the same as String.compareToIgnoreCase method 有人可以解释为什么上面两个Arrays.sort不能编译,即使它们使用的方法与String.compareToIgnoreCase方法相同

In FakeString , Your compareToIgnoreCase has a single String argument, so it can't come in place of a Comparator<String> , which requires a method with two String arguments. FakeString ,您的compareToIgnoreCase具有单个String参数,因此它不能代替Comparator<String> ,这需要具有两个String参数的方法。

In FakeString2 , your compareToIgnoreCase has an implicit FakeString argument (this) and a String argument, so, again, it can't come in place of a Comparator<String> . FakeString2 ,您的compareToIgnoreCase有一个隐式FakeString参数(this)和一个String参数,因此,它不能代替Comparator<String>

This is the difference between a method reference on some object and a method reference on the object being processed . 这是某个对象的方法引用与正在处理的对象的方法引用之间的区别。

First the Oracle examples 首先是Oracle示例

Lets look at this first case: 让我们看看第一个案例:

public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
}
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

Here, the method compareByName is called on the passed in instance of myComparisonProvider with each pair of arguments in the sort algorithm. 这里,方法compareByName被称为在实例传递myComparisonProvider用在每一对参数sort算法。

So here, when comparing a and b we actually call: 所以在这里,当比较ab我们实际调用:

final int c = myComparisonProvider.compareByName(a,b);

Now, in the second case: 现在,在第二种情况下:

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

You are sorting a String[] so the method compareToIgnoreCase is called on the String instance currently being sorted with the other String as an argument. 您正在对String[]进行排序,因此在当前正在使用另一个String作为参数进行排序的String实例上调用方法compareToIgnoreCase

So here, when comparing a and b we actually call: 所以在这里,当比较ab我们实际调用:

final int c = a.compareToIgnoreCase(b);

So these are two different cases: 所以这是两种不同的情况:

  • one where you pass in a method on an arbitrary object instance; 您在任意对象实例上传递方法的一个; and
  • one where you pass in a method to be called on the instance being processed. 传递要在正在处理的实例上调用的方法的文件。

Onto your examples 在你的例子上

Now in your first example, you also have a String[] and you try and sort it. 现在,在您的第一个示例中,您还有一个String[]并尝试对其进行排序。 So: 所以:

Arrays.sort(stringArray, FakeString::compare);

So here, when comparing a and b we actually call: 所以在这里,当比较ab我们实际调用:

final int c = FakeString.compare(a, b);

The only difference is compare is static . 唯一的区别是comparestatic

Arrays.sort(stringArray, FakeString::compareToIgnoreCase);

Now, the String[] is not a FakeString[] so we cannot call this method on String . 现在, String[]不是FakeString[]所以我们不能在String上调用这个方法。 Therefore we must be calling a static method on FakeString . 因此,我们必须在FakeString上调用static方法。 But we cannot do this either, because we require a method (String, String) -> int but we only have (String) -> int - compilation error. 但我们也不能这样做,因为我们需要一个方法(String, String) -> int但我们只有(String) -> int - 编译错误。

In the second example the problem is exactly the same, as you still have a String[] . 在第二个例子中,问题完全相同,因为你仍然有一个String[] And compareToIgnoreCase has the wrong signature. 并且compareToIgnoreCase具有错误的签名。

TL;DR: TL; DR:

The point you are missing is that in the String::compareToIgnoreCase example; 您缺少的是String::compareToIgnoreCase示例中的那个; the method is called on the String currently being processed . 当前正在处理String上调用该方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM