Lambda表达式最佳实践
文章目錄
- 簡介
- 優(yōu)先使用標(biāo)準(zhǔn)Functional接口
- 使用@FunctionalInterface注解
- 在Functional Interfaces中不要濫用Default Methods
- 使用Lambda 表達(dá)式來實(shí)例化Functional Interface
- 不要重寫Functional Interface作為參數(shù)的方法
- Lambda表達(dá)式和內(nèi)部類是不同的
- Lambda Expression盡可能簡潔
- 使用方法引用
- Effectively Final 變量
- 結(jié)論
簡介
Lambda表達(dá)式j(luò)ava 8引入的函數(shù)式編程框架。之前的文章中我們也講過Lambda表達(dá)式的基本用法。
本文將會(huì)在之前的文章基礎(chǔ)上更加詳細(xì)的講解Lambda表達(dá)式在實(shí)際應(yīng)用中的最佳實(shí)踐經(jīng)驗(yàn)。
優(yōu)先使用標(biāo)準(zhǔn)Functional接口
之前的文章我們講到了,java在java.util.function包中定義了很多Function接口。基本上涵蓋了我們能夠想到的各種類型。
假如我們自定義了下面的Functional interface:
@FunctionalInterface public interface Usage {String method(String string); }然后我們需要在一個(gè)test方法中傳入該interface:
public String test(String string, Usage usage) {return usage.method(string); }上面我們定義的函數(shù)接口需要實(shí)現(xiàn)method方法,接收一個(gè)String,返回一個(gè)String。這樣我們完全可以使用Function來代替:
public String test(String string, Function<String, String> fn) {return fn.apply(string); }使用標(biāo)準(zhǔn)接口的好處就是,不要重復(fù)造輪子。
使用@FunctionalInterface注解
雖然@FunctionalInterface不是必須的,不使用@FunctionalInterface也可以定義一個(gè)Functional Interface。
但是使用@FunctionalInterface可以在違背Functional Interface定義的時(shí)候報(bào)警。
如果是在維護(hù)一個(gè)大型項(xiàng)目中,加上@FunctionalInterface注解可以清楚的讓其他人了解這個(gè)類的作用。
從而使代碼更加規(guī)范和更加可用。
所以我們需要這樣定義:
@FunctionalInterface public interface Usage {String method(String string); }而不是:
public interface Usage {String method(String string); }在Functional Interfaces中不要濫用Default Methods
Functional Interface是指只有一個(gè)未實(shí)現(xiàn)的抽象方法的接口。
如果該Interface中有多個(gè)方法,則可以使用default關(guān)鍵字為其提供一個(gè)默認(rèn)的實(shí)現(xiàn)。
但是我們知道Interface是可以多繼承的,一個(gè)class可以實(shí)現(xiàn)多個(gè)Interface。 如果多個(gè)Interface中定義了相同的default方法,則會(huì)報(bào)錯(cuò)。
通常來說default關(guān)鍵字一般用在升級項(xiàng)目中,避免代碼報(bào)錯(cuò)。
使用Lambda 表達(dá)式來實(shí)例化Functional Interface
還是上面的例子:
@FunctionalInterface public interface Usage {String method(String string); }要實(shí)例化Usage,我們可以使用new關(guān)鍵詞:
Usage usage = new Usage() {@Overridepublic String method(String string) {return string;} };但是最好的辦法就是用lambda表達(dá)式:
Usage usage = parameter -> parameter;不要重寫Functional Interface作為參數(shù)的方法
怎么理解呢? 我們看下面兩個(gè)方法:
public class ProcessorImpl implements Processor {@Overridepublic String process(Callable<String> c) throws Exception {// implementation details}@Overridepublic String process(Supplier<String> s) {// implementation details} }兩個(gè)方法的方法名是一樣的,只有傳入的參數(shù)不同。但是兩個(gè)參數(shù)都是Functional Interface,都可以用同樣的lambda表達(dá)式來表示。
在調(diào)用的時(shí)候:
String result = processor.process(() -> "test");因?yàn)閰^(qū)別不了到底調(diào)用的哪個(gè)方法,則會(huì)報(bào)錯(cuò)。
最好的辦法就是將兩個(gè)方法的名字修改為不同的。
Lambda表達(dá)式和內(nèi)部類是不同的
雖然我們之前講到使用lambda表達(dá)式可以替換內(nèi)部類。但是兩者的作用域范圍是不同的。
在內(nèi)部類中,會(huì)創(chuàng)建一個(gè)新的作用域范圍,在這個(gè)作用域范圍之內(nèi),你可以定義新的變量,并且可以用this引用它。
但是在Lambda表達(dá)式中,并沒有定義新的作用域范圍,如果在Lambda表達(dá)式中使用this,則指向的是外部類。
我們舉個(gè)例子:
private String value = "Outer scope value";public String scopeExperiment() {Usage usage = new Usage() {String value = "Inner class value";@Overridepublic String method(String string) {return this.value;}};String result = usage.method("");Usage usageLambda = parameter -> {String value = "Lambda value";return this.value;};String resultLambda = usageLambda.method("");return "Results: result = " + result + ", resultLambda = " + resultLambda; }上面的例子將會(huì)輸出“Results: result = Inner class value, resultLambda = Outer scope value”
Lambda Expression盡可能簡潔
通常來說一行代碼即可。如果你有非常多的邏輯,可以將這些邏輯封裝成一個(gè)方法,在lambda表達(dá)式中調(diào)用該方法即可。
因?yàn)閘ambda表達(dá)式說到底還是一個(gè)表達(dá)式,表達(dá)式當(dāng)然越短越好。
java通過類型推斷來判斷傳入的參數(shù)類型,所以我們在lambda表達(dá)式的參數(shù)中盡量不傳參數(shù)類型,像下面這樣:
(a, b) -> a.toLowerCase() + b.toLowerCase();而不是:
(String a, String b) -> a.toLowerCase() + b.toLowerCase();如果只有一個(gè)參數(shù)的時(shí)候,不需要帶括號:
a -> a.toLowerCase();而不是:
(a) -> a.toLowerCase();返回值不需要帶return:
a -> a.toLowerCase();而不是:
a -> {return a.toLowerCase()};使用方法引用
為了讓lambda表達(dá)式更加簡潔,在可以使用方法引用的時(shí)候,我們可以使用方法引用:
a -> a.toLowerCase();可以被替換為:
String::toLowerCase;Effectively Final 變量
如果在lambda表達(dá)式中引用了non-final變量,則會(huì)報(bào)錯(cuò)。
effectively final是什么意思呢?這個(gè)是一個(gè)近似final的意思。只要一個(gè)變量只被賦值一次,那么編譯器將會(huì)把這個(gè)變量看作是effectively final的。
String localVariable = "Local";Usage usage = parameter -> {localVariable = parameter;return localVariable;};上面的例子中l(wèi)ocalVariable被賦值了兩次,從而不是一個(gè)Effectively Final 變量,會(huì)編譯報(bào)錯(cuò)。
為什么要這樣設(shè)置呢?因?yàn)閘ambda表達(dá)式通常會(huì)用在并行計(jì)算中,當(dāng)有多個(gè)線程同時(shí)訪問變量的時(shí)候Effectively Final 變量可以防止不可以預(yù)料的修改。
結(jié)論
lambda是一個(gè)非常有用的功能,希望小伙伴們能夠在工作中掌握。
更多精彩內(nèi)容且看:
- 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級賬本,以太坊,Libra,比特幣等持續(xù)更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續(xù)更新
- java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程
歡迎關(guān)注我的公眾號:程序那些事,更多精彩等著您!
更多內(nèi)容請?jiān)L問 www.flydean.com
總結(jié)
以上是生活随笔為你收集整理的Lambda表达式最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java并发Exchanger的使用
- 下一篇: 在java 8 stream表达式中实现