好程序員分享java8新特性之Lambda表達式

好程序員分享java8新特性之Lambda表達式

⼀、Lambda表達式簡介

什麼是Lambda?

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

爲什麼要使⽤Lambda?

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

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

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

interface Comparator {

int compare(T o1, T o2);

}

class Program {

public static void main(String[] args) {

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

class Impl implements Comparator {

@Override

public int compare(Integer o1, Integer o2) {

return o1 - o2;

}

}

Comparator c1 = new Impl();

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

Comparator c2 = new Comparator() {

@Override

public int compare(Integer o1, Integer o2) {

return o1 - o2;

}

};

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

Comparator 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); }

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

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

可以精簡爲:

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

⽅法體精簡

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

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

可以精簡爲:

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

  1. 如果⽅法體中唯⼀的⼀條語句是返回值,在精簡掉⼤括號後,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 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

IntFunction :參數:int,返回值:R

IntToDoubleFunction :參數:int,返回值:double

IntToLongFunction :參數:int,返回值:long

LongFunction :參數:long,返回值:R

LongToDoubleFunction :參數:long,返回值:double

LongToIntFunction :參數:long,返回值:int

DoubleFunction :參數: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

R>

L,

R boolean

BiConsumer

U>

T,

U void

BiFunction

U, R>

T,

U R

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章