国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - 深入淺析JDK8新特性之Lambda表達(dá)式

深入淺析JDK8新特性之Lambda表達(dá)式

2020-06-28 11:47不能說的秘密go JAVA教程

Lambda表達(dá)式主要是替換了原有匿名內(nèi)部類的寫法,也就是簡(jiǎn)化了匿名內(nèi)部類的寫法。這篇文章主要介紹了JDK8新特性之Lambda表達(dá)式,非常不錯(cuò)感興趣的朋友參考下吧

第一次是接觸Lambda表達(dá)式是在TypeScript中(JavaScript的超集中),當(dāng)時(shí)是為了讓TypeScript的this方法外而不是本方法內(nèi)所使用的。使用過后突然想到Lambda不是JDK8的重量級(jí)新特性么?于是感覺查閱相關(guān)資料并記錄下來:

一. 行為參數(shù)化

行為參數(shù)化簡(jiǎn)單的說就是函數(shù)的主體僅包含模板類通用代碼,而一些會(huì)隨著業(yè)務(wù)場(chǎng)景而變化的邏輯則以參數(shù)的形式傳遞到函數(shù)之中,采用行為參數(shù)化可以讓程序更加的通用,以應(yīng)對(duì)頻繁變更的需求。

考慮一個(gè)業(yè)務(wù)場(chǎng)景,假設(shè)我們需要通過程序?qū)μO果進(jìn)行篩選,我們先定義一個(gè)蘋果的實(shí)體:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Apple {
/** 編號(hào) */
private long id;
/** 顏色 */
private Color color;
/** 重量 */
private float weight;
/** 產(chǎn)地 */
private String origin;
public Apple() {
}
public Apple(long id, Color color, float weight, String origin) {
this.id = id;
this.color = color;
this.weight = weight;
this.origin = origin;
}
// 省略getter和setter
}

用戶最開始的需求可能只是簡(jiǎn)單的希望能夠通過程序篩選出綠色的蘋果,于是我們可以很快的通過程序?qū)崿F(xiàn):

?
1
2
3
4
5
6
7
8
9
public static List<Apple> filterGreenApples(List<Apple> apples) {
List<Apple> filterApples = new ArrayList<>();
for (final Apple apple : apples) {
if (Color.GREEN.equals(apple.getColor())) {
filterApples.add(apple);
}
}
return filterApples;
}

這段代碼很簡(jiǎn)單,沒有什么值得說的。但當(dāng)如果用戶需求變?yōu)榫G色,看起來修改代碼也很簡(jiǎn)單,無非是把判斷條件的綠色改為紅色而已。但我們需要考慮另外一個(gè)問題,如果變化條件頻繁的改變這么辦?如果只是顏色的改變,那好我們直接讓用戶把顏色的判斷條件傳遞進(jìn)來,判斷方法的參數(shù)變”要判斷的集合以及要篩選的顏色”。但如果用戶不僅僅是判斷顏色,還想判斷重量呀,大小呀什么的,怎么辦?你是不是覺得我們依次添加不同的參數(shù)來完成判斷就可以了?但這樣通過傳遞參數(shù)的方式真的好嗎?如果篩選條件越來越多,組合模式越來越復(fù)雜,我們是不是需要考慮到所有的情況,并針對(duì)每一種情況都有相應(yīng)的應(yīng)對(duì)策略呢?這個(gè)時(shí)候我們就可以將行為參數(shù)化,篩選條件抽離出來當(dāng)做參數(shù)傳遞進(jìn)來,此時(shí)我們可以封裝一個(gè)判斷的接口出來:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public interface AppleFilter {
/**
* 篩選條件抽象
*
* @param apple
* @return
*/
boolean accept(Apple apple);
}
/**
* 將篩選條件封裝成接口
*
* @param apples
* @param filter
* @return
*/
public static List<Apple> filterApplesByAppleFilter(List<Apple> apples, AppleFilter filter) {
List<Apple> filterApples = new ArrayList<>();
for (final Apple apple : apples) {
if (filter.accept(apple)) {
filterApples.add(apple);
}
}
return filterApples;
}

通過上面行為抽象化之后,我們可以在具體調(diào)用的地方設(shè)置篩選條件,并將條件作為參數(shù)傳遞到方法中,此時(shí)采用匿名內(nèi)部類的方法:

?
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
// 篩選蘋果
List<Apple> filterApples = filterApplesByAppleFilter(apples, new AppleFilter() {
@Override
public boolean accept(Apple apple) {
// 篩選重量大于100g的紅蘋果
return Color.RED.equals(apple.getColor()) && apple.getWeight() > 100;
}
});
}

這樣的設(shè)計(jì)在jdk內(nèi)部也經(jīng)常采用,比如Java.util.Comparator,java.util.concurrent.Callable等,使用這一類接口的時(shí)候,我們都可以在具體調(diào)用的地方用過匿名類來指定函數(shù)的具體執(zhí)行邏輯,不過從上面的代碼塊來看,雖然很極客,但是不夠簡(jiǎn)潔,在java8中我們可以通過lambda來簡(jiǎn)化:

?
1
2
3
4
// 篩選蘋果
List<Apple> filterApples = filterApplesByAppleFilter(apples,
(Apple apple) -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= 100);
//()->xxx ()里面就是方法參數(shù),xxx是方法實(shí)現(xiàn)

二. lambda表達(dá)式定義

我們可以將lambda表達(dá)式定義為一種 簡(jiǎn)潔、可傳遞的匿名函數(shù),首先我們需要明確lambda表達(dá)式本質(zhì)上是一個(gè)函數(shù),雖然它不屬于某個(gè)特定的類,但具備參數(shù)列表、函數(shù)主體、返回類型,以及能夠拋出異常;其次它是匿名的,lambda表達(dá)式?jīng)]有具體的函數(shù)名稱;lambda表達(dá)式可以像參數(shù)一樣進(jìn)行傳遞,從而極大的簡(jiǎn)化代碼的編寫。格式定義如下:

格式一: 參數(shù)列表 -> 表達(dá)式

格式二: 參數(shù)列表 -> {表達(dá)式集合}

需要注意的是,lambda表達(dá)式隱含了return關(guān)鍵字,所以在單個(gè)的表達(dá)式中,我們無需顯式的寫return關(guān)鍵字,但是當(dāng)表達(dá)式是一個(gè)語句集合的時(shí)候,則需要顯式添加return,并用花括號(hào){ }將多個(gè)表達(dá)式包圍起來,下面看幾個(gè)例子:

?
1
2
3
4
5
6
7
8
9
//返回給定字符串的長(zhǎng)度,隱含return語句
(String s) -> s.length()
// 始終返回42的無參方法
() -> 42
// 包含多行表達(dá)式,則用花括號(hào)括起來
(int x, int y) -> {
int z = x * y;
return x + z;
}

三. 依托于函數(shù)式接口使用lambda表達(dá)式

lambda表達(dá)式的使用需要借助于函數(shù)式接口,也就是說只有函數(shù)式接口出現(xiàn)地方,我們才可以將其用lambda表達(dá)式進(jìn)行簡(jiǎn)化。

自定義函數(shù)式接口:

函數(shù)式接口定義為只具備 一個(gè)抽象方法 的接口。java8在接口定義上的改進(jìn)就是引入了默認(rèn)方法,使得我們可以在接口中對(duì)方法提供默認(rèn)的實(shí)現(xiàn),但是不管存在多少個(gè)默認(rèn)方法,只要具備一個(gè)且只有一個(gè)抽象方法,那么它就是函數(shù)式接口,如下(引用上面的AppleFilter):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 蘋果過濾接口
*/
@FunctionalInterface
public interface AppleFilter {
/**
* 篩選條件抽象
*
* @param apple
* @return
*/
boolean accept(Apple apple);
}

 

AppleFilter僅包含一個(gè)抽象方法 accept(Apple apple),依照定義可以將其視為一個(gè)函數(shù)式接口,在定義時(shí)我們?yōu)樵摻涌谔砑恿薂FunctionalInterface注解,用于標(biāo)記該接口是函數(shù)式接口,不過這個(gè)接口是可選的,當(dāng)添加了該接口之后,編譯器就限制了該接口只允許有一個(gè)抽象方法,否則報(bào)錯(cuò),所以推薦為函數(shù)式接口添加該注解。

jdk自帶的函數(shù)式接口:

jdk為lambda表達(dá)式已經(jīng)內(nèi)置了豐富的函數(shù)式接口,下面分別就Predicate<T>、Consumer<T>、Function<T, R>的使用示例說明。

Predicate:

?
1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}

Predicate的功能類似于上面的AppleFilter,利用我們?cè)谕獠吭O(shè)定的條件對(duì)于傳入的參數(shù)進(jìn)行校驗(yàn),并返回驗(yàn)證結(jié)果boolean,下面利用Predicate對(duì)List集合的元素進(jìn)行過濾:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
*
* @param list
* @param predicate
* @param <T>
* @return
*/
public <T> List<T> filter(List<T> list, Predicate<T> predicate) {
List<T> newList = new ArrayList<T>();
for (final T t : list) {
if (predicate.test(t)) {
newList.add(t);
}
}
return newList;
}

使用:

?
1
demo.filter(list, (String str) -> null != str && !str.isEmpty());

Consumer

?
1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public interface Consumer<T> {
 
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}

Consumer提供了一個(gè)accept抽象函數(shù),該函數(shù)接收參數(shù),但不返回值,下面利用Consumer遍歷集合.

?
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 遍歷集合,執(zhí)行自定義行為
*
* @param list
* @param consumer
* @param <T>
*/
public <T> void filter(List<T> list, Consumer<T> consumer) {
for (final T t : list) {
consumer.accept(t);
}
}

利用上面的函數(shù)式接口,遍歷字符串集合,并打印非空字符串:

?
1
2
3
4
5
demo.filter(list, (String str) -> {
if (StringUtils.isNotBlank(str)) {
System.out.println(str);
}
});

Function

?
1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}

Funcation執(zhí)行轉(zhuǎn)換操作,輸入是類型T的數(shù)據(jù),返回R類型的數(shù)據(jù),下面利用Function對(duì)集合進(jìn)行轉(zhuǎn)換:

?
1
2
3
4
5
6
7
public <T, R> List<R> filter(List<T> list, Function<T, R> function) {
List<R> newList = new ArrayList<R>();
for (final T t : list) {
newList.add(function.apply(t));
}
return newList;
}

其他:

?
1
demo.filter(list, (String str) -> Integer.parseInt(str));

上面這些函數(shù)式接口還提供了一些邏輯操作的默認(rèn)實(shí)現(xiàn),留到后面介紹java8接口的默認(rèn)方法時(shí)再講吧~

使用過程中需要注意的一些事情:

類型推斷:

在編碼過程中,有時(shí)候可能會(huì)疑惑我們的調(diào)用代碼會(huì)去具體匹配哪個(gè)函數(shù)式接口,實(shí)際上編譯器會(huì)根據(jù)參數(shù)、返回類型、異常類型(如果存在)等做正確的判定。
在具體調(diào)用時(shí),在一些時(shí)候可以省略參數(shù)的類型,從而進(jìn)一步簡(jiǎn)化代碼:

?
1
2
3
4
5
6
7
// 篩選蘋果
List<Apple> filterApples = filterApplesByAppleFilter(apples,
(Apple apple) -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= 100);
// 某些情況下我們甚至可以省略參數(shù)類型,編譯器會(huì)根據(jù)上下文正確判斷
List<Apple> filterApples = filterApplesByAppleFilter(apples,
apple -> Color.R
ED.equals(apple.getColor()) && apple.getWeight() >= 100);

局部變量

上面所有例子我們的lambda表達(dá)式都是使用其主體參數(shù),我們也可以在lambda中使用局部變量,如下

?
1
2
3
int weight = 100;
List<Apple> filterApples = filterApplesByAppleFilter(apples,
apple -> Color.RED.equals(apple.getColor()) && apple.getWeight() >= weight);:

該例子中我們?cè)趌ambda中使用了局部變量weight,不過在lambda中使用局部變量必須要求該變量 顯式聲明為final或事實(shí)上的final ,這主要是因?yàn)榫植孔兞看鎯?chǔ)在棧上,lambda表達(dá)式則在另一個(gè)線程中運(yùn)行,當(dāng)該線程視圖訪問該局部變量的時(shí)候,該變量存在被更改或回收的可能性,所以用final修飾之后就不會(huì)存在線程安全的問題。

四. 方法引用

采用方法引用可以更近一步的簡(jiǎn)化代碼,有時(shí)候這種簡(jiǎn)化讓代碼看上去更加的直觀,先看一個(gè)例子:

?
1
2
3
4
5
/* ... 省略apples的初始化操作 */
// 采用lambda表達(dá)式
apples.sort((Apple a, Apple b) -> Float.compare(a.getWeight(), b.getWeight()));
// 采用方法引用
apples.sort(Comparator.comparing(Apple::getWeight));

方法引用通過::將方法隸屬和方法自身連接起來,主要分為三類:

靜態(tài)方法

?
1
(args) -> ClassName.staticMethod(args)

轉(zhuǎn)換成

?
1
ClassName::staticMethod

參數(shù)的實(shí)例方法

?
1
(args) -> args.instanceMethod()

轉(zhuǎn)換成

?
1
ClassName::instanceMethod // ClassName是args的類型

外部的實(shí)例方法

?
1
(args) -> ext.instanceMethod(args)

轉(zhuǎn)換成

?
1
ext::instanceMethod(args)

參考:

http://www.codeceo.com/article/lambda-of-java-8.html

以上所述是小編給大家介紹的JDK8新特性之Lambda表達(dá)式,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!

原文鏈接:http://blog.csdn.net/canot/article/details/52951828

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 一区二区三区视频 | 欧美做爰一区二区三区 | 亚洲免费影院 | 国产亚洲精品久久久久久久 | 老司机av导航| 91夜夜操 | 国产羞羞视频免费在线观看 | 免费看黄色一级大片 | av在线视 | 日本久久精品 | 欧美日韩精品一区二区在线观看 | 亚洲欧美高清 | 亚洲欧美激情精品一区二区 | 久青草视频在线 | 国产乱码精品一区二区三区中文 | 国产一区视频在线 | 亚洲精品国产精品国自产在线 | 97久久精品人人澡人人爽 | 欧美午夜在线观看 | 欧美日韩第一区 | 久久久精品网 | 一区二区三区高清不卡 | 黄片毛片 | 国产精品一区二区三区在线播放 | 日日干夜夜操 | 精品影视 | 成人免费观看视频大全 | 国产在线观看一区二区 | 日本中文字幕在线观看 | 欧美视频日韩视频 | jyzz中国jizz十八岁免费 | 国产视频精品免费 | 成人av免费在线 | 日韩成人在线播放 | av天天看 | 精品欧美一区二区三区久久久 | 国产黄色网址在线观看 | 久久水蜜桃| 国产激情视频 | 国产乱码一区二区三区在线观看 | 久久精品成人一区二区三区蜜臀 |