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