好程式設計師分享java8新特性之Lambda表示式

好程式設計師IT發表於2019-08-29

好程式設計師分享java8新特性之Lambda表示式

⼀、 Lambda 表示式簡介

什麼是 Lambda?

Lambda 表示式是 Java 8 推出的⼀個新特性。從本質上講, Lambda 表示式是⼀個匿名函式。

為什麼要使⽤ Lambda?

使⽤ Lambda 表示式可以對⼀個接⼝進⾏⾮常簡潔的實現。

之前我們在給⼀個接⼝引⽤賦值的時候,可以使⽤接⼝實現類,或者匿名內部類。但是有了

Lambda 表示式,我們可以更加⽅便的實現這個需求。

interface Comparator <T >  {

int compare (T o1 , T o2 );

}

class Program  {

public static void main ( String [] args ) {

// 1. 使⽤接⼝實現類實現

class Impl implements Comparator < Integer >  {

@Override

public int compare ( Integer o1 , Integer o2 ) {

return o1 - o2 ;

}

}

Comparator < Integer > c1 = new Impl ();

// 2. 使⽤匿名內部類實現

Comparator < Integer > c2 = new Comparator < Integer > () {

@Override

public int compare ( Integer o1 , Integer o2 ) {

return o1 - o2 ;

}

};

// 3. 使⽤ Lambda 表示式實現

Comparator < Integer > c3 =  (o1 , o2 ) -> o1 - o2 ;

}

}

從上述例⼦中,我們可以看到 : 對同樣⼀個接⼝引⽤的實現, Lambda 最簡單!

Lambda 對接⼝的要求? 雖然 Lambda 表示式可以很便捷的實現接⼝,但並不是所有的接⼝都可以使⽤ Lambda 表示式來實現。

可以⽤ Lambda 表示式來簡潔實現的接⼝是有要求的。因為 Lambda 表示式本質上來講,就是⼀個匿名

函式,⽤這個匿名函式來實現接⼝中的⽅法。所以,如果接⼝中有多個必須要實現抽象⽅法時,

Lambda 表示式將⽆法是⽤。

注: Lambda 表示式要求接⼝中只有⼀個必須要實現的抽象⽅法。但是 JAVA 8 對接⼝也有⼀個

擴充。現在,我們可以在接⼝中,是⽤ default 來修飾⼀個⽅法,此時,這個⽅法需要有實

現。那麼,實現類在實現接⼝的時候,對於 default ⽅法,可以實現,也可以不實現。所以,

這⾥所說的接⼝中只有⼀個必須實現的抽象⽅法,與 default ⽅法⽆關。

@FunctionalInterface**

@FunctionalInterface

因為 Lambda 表示式要求接⼝中有且只能有⼀個必須實現的抽象⽅法,所以,對接⼝可以使⽤

@FunctionalInterface 接⼝來進⾏限定。這個註解約束了接⼝中只能有⼀個必須實現的抽象⽅

法。使⽤這個註解修飾的接⼝,⼜叫做函式式接⼝。

⼆、 Lambda 表示式基礎語法

Lambda 表示式,本質上就是⼀個匿名⽅法,所以離不開⽅法的⼏個必要的組成部分:返回值、⽅法

名、引數、⽅法體。但是由於他是⼀個匿名⽅法,所以⽅法名可以忽略。同時, Lambda 中也不需要

顯式宣告返回值型別。所以, 我們在寫 Lambda 表示式的時候,只需要關⼼引數和⽅法體即可。

引數: () 包圍起來,多個引數以逗號分隔

(int a, int b)

⽅法體: {} 包圍起來

{ System.out.println("hello world"); }

->  Lambda 運算子,⽤來分隔引數和⽅法體

(int a, int b) -> {};

有了這⼏個組成部分,我們就可以對任意的函式式接⼝使⽤ Lambda 進⾏實現

// ⽆參、⽆返回值

() ->  { System .out .println ( "hello world" ); };

// int, int 引數、⽆返回值

( int a , int b ) ->  { System .out .println (a + b ); };

// int, int 引數、 int 返回值

( int a , int b ) ->  { return a + b ; };

三、 Lambda 表示式語法精簡

接⼝中定義的⽅法,已經宣告瞭⽅法的引數型別、數量和返回值型別。所以,使⽤ Lambda 表示式在

實現的時候,對應的部分可以省略 引數精簡

1. 引數的型別可以精簡

(int a, int b) -> { System.out.println(a + b); }

可以精簡為:

(a, b) -> { System.out.println(a + b); }

2. 如果引數數量只有⼀個,⼩括號可以精簡

(int a) -> { System.out.println(a); }

可以精簡為:

a -> { System.out.println(a); }

⽅法體精簡

1. 如果⽅法體中只有⼀條語句,則⼩括號可以省略

a -> { System.out.println(a); }

可以精簡為:

a -> System.out.println(a);

2. 如果⽅法體中唯⼀的⼀條語句是返回值,在精簡掉⼤括號後, return 也必須省略

a -> { return a * 2; }

可以精簡為:

a -> a * 2;

四、 Lambda 表示式語法進階之⽅法引⽤

什麼是⽅法引⽤

如果在使⽤ Lambda 進⾏接⼝實現的時候,需要實現的邏輯已經在某⼀個⽅法中實現,則可以直接使

⽤⽅法引⽤,指向指定的⽅法。

interface Calculate  {

int calculate ( int a , int b );

}

public class Program  {

public static void main ( String [] args ) {

// 接⼝引⽤

Calculate c =  (a , b ) -> a + b ;

}

public static int add ( int a , int b ) {

return a + b ;

}

} 在上述程式碼中, main 函式中 Calculate 引⽤ c 的實現部分,下⾯已經有⼀個⽅法 add 進⾏了實現。

所以此時,我們不需要再實現⼀次,只需要直接指向已經寫好的實現即可。所以,可以進⾏如下改

造:

Calculate c = Program ::add ;

上⾯的 Program::add 就是⼀個⽅法引⽤。引⽤了 Program 類中的⼀個靜態⽅法 add

在使⽤⽅法引⽤的時候需要注意

1. 引⽤的⽅法引數數量、引數型別、返回值型別必須和函式式接⼝中的⽅法定義⼀致。

2. ⽅法引⽤必須有引⽤主體,即⽅法的⾪屬者。例如:上⽅的 add ⽅法是⼀個靜態⽅法,需要使⽤

類來調⽤。所以⽅法引⽤就是 類 :: ⽅法,如果是⼀個成員⽅法,則需要使⽤ 物件 :: ⽅法 的

形式來引⽤。

構造⽅法的引⽤

如果需要引⽤⼀個構造⽅法,需要使⽤ ::new 進⾏引⽤

interface CreatePerson  {

Person getPerson ();

}

class Person  {}

class Program  {

public static void main ( String [] args ) {

CreatePerson c = Person :: new ;

}

}

五、 Lambda 表示式之綜合案例 : 排序 Comparator

// 排序

list .sort ((o1 , o2 ) -> o2 .age - o1 .age );

// 使⽤ Lambda 表示式來實現 Comparator 接⼝,並例項化⼀個 TreeSet 物件

TreeSet <Person > set = new TreeSet <> ((o1 , o2 ) ->  {

if  (o1 .age >= o2 .age ) {

return - 1 ;

}

else  {

return 1 ;

}

});

六、 Lambda 表示式之綜合案例 : forEach() // 將集合中的每⼀個元素都帶⼊到⽅法 accept 中。

list .forEach (System .out ::println );

// 輸出集合中所有的偶數

list .forEach (ele ->  {

if  (ele % 2 == 0 ) {

System .out .println (ele );

}

});

七、 Lambda 表示式之綜合案例 : removeIf()

// 將集合中的每⼀個元素都帶⼊到 test ⽅法中 , 如果返回值是 true ,則刪除這個元素

// 刪除集合中的年齡⼤於 10 歲的元素

list .removeIf (ele -> ele .age > 10 );

⼋、 Lambda 表示式之綜合案例 : 執行緒例項化

new Thread (() ->  {

for  ( int i = 0 ; i < 100 ; i ++ ) {

System .out .println (i );

}

}).start ();

九、系統內建函式式接⼝

系統已經給我們提供了很多函式式接⼝,⽅便我們的使⽤。因此,如果我們需要⽤到以下⽅法的時

候,不需要再設計接⼝,直接使⽤指定的接⼝即可。 函式式接⼝

返回值 特殊說明:⼏個特殊實現的⼦接⼝

Predicate T boolean

IntPredicate 引數: int ,返回值: boolean

LongPredicate 引數: long ,返回值: boolean

DoublePredicate 引數: double ,返回值: boolean

Consumer T void

IntConsumer 引數: int ,返回值: void LongConsumer

引數: int ,返回值: void DoubleConsumer 引數: int ,返

回值: void

Function<T, R> T R

IntFunction<R> 引數: int ,返回值: R

IntToDoubleFunction 引數: int ,返回值: double

IntToLongFunction 引數: int ,返回值: long

LongFunction<R> 引數: long ,返回值: R

LongToDoubleFunction 引數: long ,返回值: double

LongToIntFunction 引數: long ,返回值: int

DoubleFunction<R> 引數: double ,返回值: R

DoubleToIntFunction 引數: double ,返回值: int

DoubleToLongFunction 引數: double ,返回值: long

Supplier T

BooleanSupplier 引數:⽆,返回值: boolean

IntSupplier 引數:⽆,返回值: int LongSupplier

數:⽆,返回值: long DoubleSupplier 引數:⽆,返回值:

double

UnaryOperator T T

IntUnaryOperator 引數: int ,返回值: int

LongUnaryOperator 引數: long ,返回值: long

DoubleUnaryOperator 引數: double ,返回值: double

BinaryOperator T,

T T

IntBinaryOperator 引數: int, int ,返回值: int

LongBinaryOperator 引數: long, long ,返回值: long

DoubleBinaryOperator 引數: double, double ,返回值:

double

BiPredicate<L,

R>

L,

R boolean

BiConsumer<T,

U>

T,

U void

BiFunction<T,

U, R>

T,

U R

上述接⼝中,最常⽤的是  Predicate Consumer


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2655451/,如需轉載,請註明出處,否則將追究法律責任。

相關文章