1. 程式人生 > >Java 8 In Action之引用特定型別的任意物件的例項方法

Java 8 In Action之引用特定型別的任意物件的例項方法

此種引用型別名稱原文為:reference to an instance method of an arbitrary object of a particular type

今天在和同學討論另外一個問題的時候(直接導致這個問題只有明天再解決了),突然爭論到能不能用類來呼叫例項方法,沒想到由此又發現了一個知識盲區。
oracle官網文件和Java 8 In Action都沒有怎麼講清楚這個問題。

方法引用總共有如下四種類型,這裡只介紹第三種,其餘三種都較為簡單,如有需要,請參見他人部落格。

 型別                                     示例

引用物件的例項方法 Object::instanceMethodName
引用類的靜態方法  ClassName::staticMethodName
引用類的例項方法 ClassName::methodName
引用構造方法 ClassName::new

第三種引用類的例項方法???這個名字相當的不準確,在Java 8 In Action是這樣介紹的,指向任意型別例項方法的方法引用(我覺得叫類的任意物件的例項方法引用更直觀)。我開始一直想當然的就認為是類::例項方法這樣就可以了,結果寫了幾個發現都用不了,看了官網給出的示例發現又可以,於是,作為當代優秀青年,怎麼可能不解決這個問題呢。

官網給出的示例:

String [] stringArray = {“芭芭拉”,“詹姆斯”,“瑪麗”,“約翰”,
    “Patricia”,“Robert”,“Michael”,“Linda”};
Arrays.sort(stringArray,String :: compareToIgnoreCase);


方法引用的等效lambda表示式String::compareToIgnoreCase將具有形式引數列表(String a, String b),其中a和b是用於更好地描述此示例的任意名稱。方法引用將呼叫該方法a.compareToIgnoreCase(b)。我反正是沒看懂這是講的啥。之後再查了下,原文是這樣的 “ reference to an instance method of an arbitrary object of a particular type ”  arbitrary 任意的, particular 特定的,翻譯過來就是引用特定型別的任意物件的例項方法。於是乎,知道了類的例項方法呼叫是有講究的。那麼,有什麼樣的條件呢。

public class test1 {
    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("Jack1", 88));
        list.add(new Student("Jack2", 81));
        list.add(new Student("Jack3", 82));
        list.add(new Student("Jack4", 83));
        list.add(new Student("Jack5", 84));
        list.add(new Student("Jack6", 85));
        list.sort(Student::compareByScore);
        System.out.println(list);
    }
}

class Student {
    private String name;
    private int score;

    public Student(){

    }

    public Student(String name,int score){
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int compareByScore(Student student){
        return this.getScore() - student.getScore();
    }

    @Override
    public String toString(){
        return this.name + "  " + this.score + "  ";
    }
}


list.sort接受一個Comparator,Comparator需要實現compare方法,lambda形式 (v1,v2)-> {dosth;return intval;}。這裡的compareByScore就是這種lambda形式的方法引用。

如果將上面的compareByScore方法改成如下形式,為什麼又要報錯了,我不就多傳了一個引數進去麼,其他的啥也沒做啊。

 public int compareByScore(Student student1, Student student2){
        return this.getScore() - student1.getScore();
    }


不好意思,它要求介面方法的引數必須比引用方法的引數多一個。而且第一個引數要是該引用方法的所在型別的或其父類,除介面方法的第一個引數以外, 其餘引數的型別要求一樣。這一段話,有些難以理解,看下面的程式碼就會明白了。

example 1

public  class Test1 {
    public void a(){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
@FunctionalInterface
interface MyInter {
    //入參引數比Test1的a方法多一個,且Test1::a的Test1與該入參型別Test1相同
    public void d(Test1 d);
}


example 2

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
@FunctionalInterface
interface MyInter {
    //該介面引數比上述的a方法引數數量多一個,除去第一個,其它型別一致(可相容,如可以一個int,一個Integer)
    //且Test1::a的Test1是該入參型別Test1相同
    public void d(Test1 d,int param1,int param2);
}

example 3
 

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
class Test2 extends Test1 {
}
@FunctionalInterface
interface MyInter {
    //該介面引數比上述的a方法引數數量多一個,除去第一個,其它型別一致(可相容,如可以一個int,一個Integer)
    //且Test1::a的Test1是該入參型別Test2的子類(不可顛倒)
    public void d(Test2 d,int param1,int param2);
}

example 4
 

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = (j,k,l)->j.a(k, l);
        //第一個引數為方法目標,其餘引數為引數
    }
}
@FunctionalInterface
interface MyInter {
    public void d(Test1 d,int param1,int param2);
}

看到這你應該就懂了,這個指向任意型別例項方法的方法引用有兩個要求:
       第一點:介面方法的引數比引用方法的引數多一個
       第二點:介面方法的第一個引數恰巧是呼叫引用方法的物件(其引用方法所在類或其父類的例項)
       如有不當之處,望指正。
參考文獻:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
                   https://stackoverflow.com/questions/32855138/how-does-a-method-reference-to-an-instance-method-of-an-arbitrary-object-of-a-p
                   https://stackoverflow.com/questions/25512532/instance-method-reference-and-lambda-parameters
                   https://segmentfault.com/a/1190000012269548
                   https://blog.csdn.net/qwe125698420/article/details/53415746
                   https://blog.csdn.net/learningcoding/article/details/72539918
                   https://blog.idrsolutions.com/2015/02/java-8-method-references-explained-5-minutes/
                  
 

相關推薦

Java 8 In Action引用特定型別任意物件例項方法

此種引用型別名稱原文為:reference to an instance method of an arbitrary object of a particular type 今天在和同學討論另外一個問題的時候(直接導致這個問題只有明天再解決了),突然爭論到能不能用類來呼叫

Java 8實戰(Java 8 in action)學習總結(三)

Streams API可以表達複雜的資料處理查詢。常用的流操作如下表: 你可以使用filter、distinct、skip和limit對流做篩選和切片。 你可以使用map和flatMap提取或轉換流中的元素。 你可以使用findFirst和findAny方法查詢流中的元素。你可以allMatch、none

Java 8 in Action》Chapter 1:為什麼要關心Java 8

自1998年 JDK 1.0(Java 1.0) 釋出以來,Java 已經受到了學生、專案經理和程式設計師等一大批活躍使用者的歡迎。這一語言極富活力,不斷被用在大大小小的專案裡。從 Java 1.1(1997年) 一直到 Java 7(2011年),Java 通過增加新功能,不斷得到良好的升級。Java 8

Java 8 in Action》Chapter 3:Lambda表示式

1. Lambda簡介 可以把Lambda表示式理解為簡潔地表示可傳遞的匿名函式的一種方式:它沒有名稱,但它有引數列表、函式主體、返回型別,可能還有一個可以丟擲的異常列表。 匿名——我們說匿名,是因為它不像普通的方法那樣有一個明確的名稱:寫得少而想得多! 函式——我們說它是函式,是因為Lambda函式不像方

Java 8 in Action》Chapter 4:引入流

1. 流簡介 流是Java API的新成員,它允許你以宣告性方式處理資料集合(通過查詢語句來表達,而不是臨時編寫一個實現)。就現在來說,你可以把它們看成遍歷資料集的高階迭代器。此外,流還可以透明地並行處理。讓我們來看一個例項返回低熱量(<400)的菜餚名稱: Java7版本: List<Dish&

Java 8 in Action》Chapter 6:用流收集資料

1. 收集器簡介 collect() 接收一個型別為 Collector 的引數,這個引數決定了如何把流中的元素聚合到其它資料結構中。Collectors 類包含了大量常用收集器的工廠方法,toList() 和 toSet() 就是其中最常見的兩個,除了它們還有很多收集器,用來對資料進行對複雜的轉換。 指令式

Java 8 in Action》Chapter 7:並行資料處理與效能

在Java 7之前,並行處理資料集合非常麻煩。第一,你得明確地把包含資料的資料結構分成若干子部分。第二,你要給每個子部分分配一個獨立的執行緒。第三,你需要在恰當的時候對它們進行同步來避免不希望出現的競爭條件,等待所有執行緒完成,最後把這些部分結果合併起來。Java 7引入了一個叫作分支/合併的框架,讓這些操

Java 8 in Action》Chapter 8:重構、測試和除錯

我們會介紹幾種方法,幫助你重構程式碼,以適配使用Lambda表示式,讓你的程式碼具備更好的可讀性和靈活性。除此之外,我們還會討論目前比較流行的幾種面向物件的設計模式, 包括策略模式、模板方法模式、觀察者模式、責任鏈模式,以及工廠模式,在結合Lambda表示式之後變得更簡潔的情況。最後,我們會介紹如何測試和除

Java 8 in Action》Chapter 9:預設方法

傳統上,Java程式的介面是將相關方法按照約定組合到一起的方式。實現介面的類必須為介面中定義的每個方法提供一個實現,或者從父類中

Java 8 in Action》Chapter 10:用Optional取代null

1965年,英國一位名為Tony Hoare的電腦科學家在設計ALGOL W語言時提出了null引用的想法。ALGOL W是第一批在堆上分配記錄的型別語言之一。Hoare選擇null引用這種方式,“只是因為這種方法實現起來非常容易”。雖然他的設計初衷就是要“通過編譯器的自動檢測機制,確保所有使用引用的地方都

Java 8 in Action》Chapter 11:CompletableFuture:組合式非同步程式設計

某個網站的資料來自Facebook、Twitter和Google,這就需要網站與網際網路上的多個Web服務通訊。可是,你並不希望因為等待某些服務的響應,阻塞應用程式的執行,浪費數十億寶貴的CPU時鐘週期。比如,不要因為等待Facebook的資料,暫停對來自Twitter的資料處理。 第7章中介紹的分支/合

java 8新特性方法引用

方法引用通過方法的名字來指向一個方法。 方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼。 方法引用使用一對冒號 :: 。 下面,我們在 Car 類中定義了 4 個方法作為例子來區分 Java 中 4 種不同方法的引用。 public class Car {

Java 8新特性接口改善(八惡人-1)

1.8 我想 when 直接 有一個 圖片 class java類 聖誕節 Daisy Donergue 多莫歌·黛西 “By woman, you mean her?” 她也能叫女人?   Java 8在13年9月發布,寫這篇博文的時間已經是17年12月份了。

Java 8新特性 並行和並行數組(八惡人-8

都是 class chm 請求 external syntax 匹配 main jvm Jody Domingre 多莫歌·喬迪 “How you doing, dummy?” 你還好嗎,傻瓜 一、基本介紹   Java8不僅增加了Stream,而且還增加了para

java 8新特性收集器,Optional類

一.收集器介面 Collectors類的靜態工廠方法能夠建立的所有收集器總結: 所有這些收集器都是對Collector介面的實現,以下時Collector介面宣告的五個方法: 二.Optional類 是一個容器類,代表一個值存在或不存在,這樣就避免了和null檢查相關的bug

Java 8新特性Optional取代null

NullPointerException,大家應該都見過。這是Tony Hoare在設計ALGOL W語言時提出的null引用的想法,他的設計初衷是想通過編譯器的自動檢測機制,確保所有使用引用的地方都是絕對安全的。很多年後,他對自己曾經做過的這個決定而後悔不已,把它稱為“我價值百萬的重大失誤”。它帶來的後果就

Java 8新特性新的日期和時間API

在Java 1.0中,對日期和時間的支援只能依賴java.util.Date類。這個類只能以毫秒的精度表示時間。這個類還有很多糟糕的問題,比如年份的起始選擇是1900年,月份的起始從0開始。這意味著你要想表示2018年8月22日,就必須建立下面這樣的Date例項: Date date = new Date

Java 8新特性CompletableFuture:組合式非同步程式設計

隨著多核處理器的出現,提升應用程式的處理速度最有效的方式就是可以編寫出發揮多核能力的軟體,我們已經可以通過切分大型的任務,讓每個子任務並行執行,使用執行緒的方式,分支/合併框架(Java 7) 和並行流(Java 8)來實現。 現在很多大型的網際網路公司都對外提供了API服務,比如百度的地圖,微博的新聞,天

Java基礎知識回顧常用資料型別的包裝類

Java基礎知識回顧之常用資料型別 Java基礎知識回顧之常用資料型別的包裝類 簡介 Java 雖然是一門面向物件的程式語言,但是其包括的8種基本資料型別並不支援面向物件的程式設計機制。也就說基本資料型別不具備“物件”的特性。例如:沒有屬性、沒有方法可以呼叫。 為了解決8個基

java 8 新特性Stream的排序/分類

  Stream簡介 Stream是Java8提供的一個新的API,它位於java.util.stream包下。Stream API提供了一種新的方式來對Java集合進行操作,這種操作方式極大的提高了Java程式設計師的生產力,讓程式設計師寫出高效率、乾淨、簡潔的程式碼。我們可以將元素集合看作一