Java中的類型推斷和lambda表達式

簡介

java是強類型的編程語言,每一個java中使用到的變量都須要定義它的類型,不然會編譯失敗。強類型語言的好處就是能夠儘量的在編譯期間就發現代碼中可能出現的問題,從而減小在運行時出現問題的可能性。java

相對的,強類型語言的缺點就是不那麼的靈活多變,寫起來比較冗餘。git

JDK8以前,java是不支持類型推斷的,在JDK8中,引入了lambda表達式,今後類型推斷產生了。程序員

本文將會講解類型推斷在lambda表達式中的最佳實踐和在使用中應該注意的事項。github

更多精彩內容且看:編程

更多內容請訪問 www.flydean.com

類型的顯示使用

假如咱們定義了一個CustUser類,而且其中有age和name兩個屬性:編程語言

@Data
@AllArgsConstructor
public class CustUser {
    int age;
    String name;
}

看下咱們怎麼在Stream中顯示使用類型:函數

public static void testStream(){
        Stream.of(new CustUser(10,"alice"), new CustUser(20,"bluce"))
                .forEach( (CustUser custUser)-> System.out.println(custUser.name));
    }

上面的例子中,咱們構建了一個CustUser類型的Stream,並在forEach方法中對CustUser進行處理。性能

forEach接收一個Consumer對象,Consumer須要實現void accept(T t)方法。由於Consumer函數接口,咱們可使用lambda表達式來替換。區塊鏈

這裏,咱們顯示傳入一個CustUser類型。代碼編譯是沒有問題的,可是看起來複雜了點。接下來咱們看下怎麼在Stream中使用類型推斷。.net

Stream中的類型推斷

上面的例子,咱們能夠改寫成這樣:

public static void testInference(){
        Stream.of(new CustUser(10,"alice"), new CustUser(20,"bluce"))
                .forEach(custUser-> System.out.println(custUser.name));
    }

這裏咱們並無定義custUser的類型,可是java能夠從Stream中的類型推斷出來。因此這樣寫是沒有問題的,能夠正常經過編譯。

類型推斷中變量名字的重要性

上面的例子中,咱們將變量的名字定義爲custUser,查看代碼的人一眼就能夠看出來這個參數表示的是CustUser類型的custUser參數。

名字寫的有意義能夠很大程度上提高代碼的可讀性和可維護性。若是你這樣寫:

forEach(u-> System.out.println(u.name)

雖然代碼變得更短了,可是失去了可讀的意義,一眼看過去,你們並不知道你這個u表明的是什麼,從而影響了代碼的可讀性。

因此變量名的定義必定要有意義。

類型推斷對性能的影響

類型推斷是個好東西,那麼有同窗會問了,類型推斷對於java的性能會有影響嗎?

咱們能夠把java分紅編譯和運行兩部分。類型推斷是在編譯期間作的事情,可能使用類型推斷會延長代碼編譯的時間,可是對運行時的效率是沒有影響的。

通常來講,咱們關注程序的性能問題是在運行時而不是編譯時,因此類型推斷對性能是沒有影響的。

類型推斷的限制

java雖然有類型推斷,可是這個推斷是有必定的限制的,它並不可以像人同樣去思考,可是也已經足夠智能了。下面咱們舉個例子:

public static Comparator<CustUser> createUser1(){
        return (CustUser user1, CustUser user2) -> user1.getAge() - user2.getAge();
    }

上面的例子中,咱們須要建立一個Comparator,使用lambda表達式咱們能夠生成一個Comparator。

Comparator須要實現方法int compare(T o1, T o2),傳入兩個參數,返回一個int。

上面例子中,咱們顯示指定了兩個參數的類型是CustUser,編譯沒有問題。

若是不顯示指定CustUser類型能夠嗎?

public static Comparator<CustUser> createUser2(){
        return (user1, user2) -> user1.getAge() - user2.getAge();
    }

答案也是能夠的。這個例子中,咱們並無傳入user1,user2,java是怎麼找到user1和user2的類型呢?

注意,上面的例子中,咱們定義了返回類型是CustUser的,Java經過這個返回類型來推斷出傳入的實際類型就是CustUser的。是否是很智能。

若是咱們將上面的return語句拆分紅兩條,會出現問題問題呢?

Comparator comparator=(user1, user2) -> user1.getAge() - user2.getAge();

這時候就會編譯報錯,說找不到getAge方法。這是由於咱們返回的Comparator並無指明類型,因此默認狀況下是Object類型。Object類型並無getAge方法,因此報錯。

咱們能夠這樣改寫:

Comparator<CustUser> comparator=(user1, user2) -> user1.getAge() - user2.getAge();

編譯完成,沒有錯誤。

總結

除了JDK8中引入的lambda表示中使用了類型推斷,其實JDK10中的var本地變量類型也是用到了類型推斷,詳請參考JDK10的新特性:本地變量類型var

本文的例子[https://github.com/ddean2009/
learn-java-base-9-to-20](https://github.com/ddean2009/...

本文做者:flydean程序那些事

本文連接:http://www.flydean.com/java-type-inference-lambda/

本文來源:flydean的博客

歡迎關注個人公衆號:程序那些事,更多精彩等着您!

相關文章
相關標籤/搜索