摘要:方法引用眾所周知,在中我們可以使用方法引用。為什么呢這是因?yàn)榉椒ㄒ貌⒎潜磉_(dá)式或者函數(shù)接口。有關(guān)方法引用的使用方式,我們又向前邁進(jìn)了一步。我們有一個(gè)工具類,可以讓每個(gè)方法引用都轉(zhuǎn)換為標(biāo)準(zhǔn)包中任意匹配的函數(shù)接口。
【編者按】本文作者為擁有15年 Java 開發(fā)經(jīng)驗(yàn)的資深程序員 Per-?ke Minborg,主要介紹如何靈活地解析 Java 中的方法引用。文章系國內(nèi) ITOM 管理平臺(tái) OneAPM 編譯呈現(xiàn)。
方法引用眾所周知,在Java 8中我們可以使用方法引用。譬如,在我們需要遍歷流元素時(shí),可以使用 String::isEmpty 來引用isEmpty方法。試看下面這段代碼:
Stream.of("A", "", "B").filter(Stream::isEmpty).count();
運(yùn)行的結(jié)果為1(因?yàn)樵谶@個(gè)流中只有一個(gè)空元素)。但是,如果我們要過濾出非空字符串,我們得寫成.filter(s -> !s.isEmpty())。這是一個(gè)Lambda表達(dá)式。顯然,這兒有個(gè)討厭的不對稱想象。我們可以使用方法引用,但卻不能用它的反式。我們可以寫predicate.negate()卻不能寫Stream::isEmpty.negate()或!Stream::isEmpty。
為什么呢?這是因?yàn)榉椒ㄒ貌⒎荓ambda表達(dá)式或者函數(shù)接口。不過,使用Java的類型推導(dǎo)可以將方法引用解析為一個(gè)或多個(gè)函數(shù)接口。上例中的String::isEmpty至少可以解析為:
PredicateFunction
所以,我們要排除其他可能性,確定到底將方法引用轉(zhuǎn)換為哪個(gè)函數(shù)接口。本文在一定程度上解決了該問題。文中的代碼來自開源項(xiàng)目Speedment,它讓數(shù)據(jù)庫看起來像Java 8的流。
解析方法引用其實(shí),以靜態(tài)方法為“管道”,可以部分地解決這個(gè)問題——該靜態(tài)方法以一個(gè)方法引用為輸入,以特定的函數(shù)接口為其返回。試考慮下面這個(gè)簡短的靜態(tài)方法:
public staticPredicate as(Predicate predicate) { return predicate; }
現(xiàn)在,如果靜態(tài)地導(dǎo)入這個(gè)方法,事實(shí)上,我們就能更簡單地使用方法引用。如下例所示:
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();
這段代碼返回的結(jié)果為2,即流中非空元素的數(shù)量。有關(guān)方法引用的使用方式,我們又向前邁進(jìn)了一步。另一個(gè)好處是,這個(gè)解決方案讓我們更輕松地編寫predicates接口,例如:
.filter(as(String::isEmpty).negate().and("A"::equals))解析所有方法引用
但是,現(xiàn)在仍有一個(gè)問題亟待解決。我們不能隨隨便便地創(chuàng)建一大堆靜態(tài)as()函數(shù),因?yàn)橐粋€(gè)方法引用可能解析為多種as()方法,正如本文開頭提到的那樣。所以,一個(gè)更妙的解決方案,是把函數(shù)接口類型名添加至每個(gè)靜態(tài)方法,這樣我們就可以程序化地為每個(gè)函數(shù)接口轉(zhuǎn)換方法選擇一個(gè)特定的方法引用。我們有一個(gè)工具類,可以讓每個(gè)方法引用都轉(zhuǎn)換為Java標(biāo)準(zhǔn)包 `java.util.function中任意匹配的函數(shù)接口。
直接在GitHub下載最新版本
import java.util.function.*; /** *
@author Per Minborg
*/
class FunctionCastUtil {
public staticBiConsumer asBiConsumer(BiConsumer biConsumer) { return biConsumer; } public static BiFunction asBiFunction(BiFunction biFunction) { return biFunction; } public static BinaryOperator asBinaryOperator(BinaryOperator binaryOperator) { return binaryOperator; } public static BiPredicate asBiPredicate(BiPredicate biPredicate) { return biPredicate; } public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) { return booleanSupplier; } public static Consumer asConsumer(Consumer consumer) { return consumer; } public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) { return doubleBinaryOperator; } public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) { return doubleConsumer; } public static DoubleFunction asDoubleFunction(DoubleFunction doubleFunction) { return doubleFunction; } public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) { return doublePredicate; } public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) { return doubleToIntFunctiontem; } public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) { return doubleToLongFunction; } public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) { return doubleUnaryOperator; } public static Function asFunction(Function function) { return function; } public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) { return intBinaryOperator; } public static IntConsumer asIntConsumer(IntConsumer intConsumer) { return intConsumer; } public static IntFunction asIntFunction(IntFunction intFunction) { return intFunction; } public static IntPredicate asIntPredicate(IntPredicate intPredicate) { return intPredicate; } public static IntSupplier asIntSupplier(IntSupplier intSupplier) { return intSupplier; } public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) { return intToDoubleFunction; } public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) { return intToLongFunction; } public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) { return intUnaryOperator; } public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) { return longBinaryOperator; } public static LongConsumer asLongConsumer(LongConsumer longConsumer) { return longConsumer; } public static LongFunction asLongFunction(LongFunction longFunction) { return longFunction; } public static LongPredicate asLongPredicate(LongPredicate longPredicate) { return longPredicate; } public static LongSupplier asLongSupplier(LongSupplier longSupplier) { return longSupplier; } public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) { return longToDoubleFunction; } public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) { return longToIntFunction; } public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) { return longUnaryOperator; } public static ObjDoubleConsumer asObjDoubleConsumer(ObjDoubleConsumer objDoubleConsumer) { return objDoubleConsumer; } public static ObjIntConsumer asObjIntConsumer(ObjIntConsumer objIntConsumer) { return objIntConsumer; } public static ObjLongConsumer asObjLongConsumer(ObjLongConsumer objLongConsumer) { return objLongConsumer; } public static Predicate asPredicate(Predicate predicate) { return predicate; } public static Supplier asSupplier(Supplier supplier) { return supplier; } public static ToDoubleBiFunction asToDoubleBiFunction(ToDoubleBiFunction toDoubleBiFunction) { return toDoubleBiFunction; } public static ToDoubleFunction asToDoubleFunction(ToDoubleFunction toDoubleFunction) { return toDoubleFunction; } public static ToIntBiFunction asToIntBiFunction(ToIntBiFunction toIntBiFunction) { return toIntBiFunction; } public static ToIntFunction asToIntFunction(ToIntFunction ioIntFunction) { return ioIntFunction; } public static ToLongBiFunction asToLongBiFunction(ToLongBiFunction toLongBiFunction) { return toLongBiFunction; } public static ToLongFunction asToLongFunction(ToLongFunction toLongFunction) { return toLongFunction; } public static UnaryOperator asUnaryOperator(UnaryOperator unaryOperator) { return unaryOperator; } private FunctionCastUtil() { }
}
在靜態(tài)導(dǎo)入了相關(guān)方法之后,我們就可以這樣寫:
Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();一個(gè)更好的解決方案
如果函數(shù)接口本身就包含一個(gè)接收方法引用并將其轉(zhuǎn)換為某類函數(shù)接口的靜態(tài)方法,那就更好了。舉例來說,標(biāo)準(zhǔn)的Java Predicated函數(shù)接口就會(huì)變成這樣:
@FunctionalInterface public interface Predicate{ boolean test(T t); default Predicate and(Predicate super T> other) {...} default Predicate negate() {...} default Predicate or(Predicate super T> other) {...} static Predicate isEqual(Object targetRef) {...} // New proposed support method to return a // Predicate view of a Functional Reference public static Predicate of(Predicate predicate) { return predicate; } }
因此,我們可以這樣寫:
Stream.of("A", "", "B").filter(Predicate.of(String::isEmpty).negate()).count();
筆者覺得這樣看起來好極了!
快聯(lián)系離你最近的Open JDK開發(fā)人員,提出你的修改建議吧!
OneAPM 能為您提供端到端的 Java 應(yīng)用性能解決方案,我們支持所有常見的 Java 框架及應(yīng)用服務(wù)器,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸,定位異常根本原因。分鐘級部署,即刻體驗(yàn),Java 監(jiān)控從來沒有如此簡單。想閱讀更多技術(shù)文章,請?jiān)L問 OneAPM 官方技術(shù)博客。
本文轉(zhuǎn)自 OneAPM 官方博客
原帖地址:https://dzone.com/articles/put-your-java-8-method-references-to-work
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65913.html
摘要:方法引用在之前只能進(jìn)行值傳遞,方法是不能傳遞的。首先方法接受了一個(gè)類型的對象,方法是獲取所有的文件,是用來存儲(chǔ)篩選之后的元素,循環(huán)所有獲得到的文件數(shù)組,然后調(diào)用中的方法來進(jìn)行條件篩選,放入后返回。 方法引用: 在Java 8之前只能進(jìn)行值傳遞,方法是不能傳遞的。如果你想調(diào)用一個(gè)方法你必須先獲取到它所在的類的實(shí)例,然后再通過實(shí)例去調(diào)用這個(gè)方法,但是Java 8新增了方法引用這個(gè)新特性可以...
摘要:目錄介紹問題匯總具體問題好消息博客筆記大匯總年月到至今,包括基礎(chǔ)及深入知識(shí)點(diǎn),技術(shù)博客,學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善開源的文件是格式的同時(shí)也開源了生活博客,從年 目錄介紹 00.Java問題匯總 01.具體問題 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技...
摘要:于是抽時(shí)間看了看以后各個(gè)版本的特性,做了一個(gè)總結(jié)。年和公開版本發(fā)布,取名為。此后對應(yīng)版本就是,。發(fā)布,是一個(gè)重大版本更新。在此之后,就是每六個(gè)月發(fā)布一次新版本。以上和參考資料聊了一些關(guān)于的歷史,下面我們看看各個(gè)版本有那些新特性。 【這是 ZY 第 11 篇原創(chuàng)技術(shù)文章】 某天在網(wǎng)上閑逛,突然看到有篇介紹 Java 11 新特性的文章,頓時(shí)心里一驚,畢竟我對于 Java 的版本認(rèn)識(shí)...
摘要:方法的基本組成包括名稱參數(shù)返回值方法體方法名和參數(shù)列表唯一的標(biāo)識(shí)出某個(gè)方法。如果返回的類型是,則的作用僅是退出方法否則必須返回正確的返回值包名名字可見性約定以域名反轉(zhuǎn)作為包名,用來劃分子目錄,并且全部小寫。 點(diǎn)擊進(jìn)入我的博客 2.1用引用操縱對象 盡管一切都看作對象,但操縱的標(biāo)識(shí)符實(shí)際上是對象的一個(gè)引用。 String s; // s是一個(gè)String類型的引用, 并沒有任何對象與其...
摘要:表達(dá)式簡介表達(dá)式是一個(gè)匿名函數(shù)對于而言并不很準(zhǔn)確,但這里我們不糾結(jié)這個(gè)問題。如果表達(dá)式的正文有一條以上的語句必須包含在大括號代碼塊中,且表達(dá)式的返回值類型要與匿名函數(shù)的返回類型相同。 版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請注明出處:https://segmentfault.com/a/1190000009186509 1. 引言 在 Java 8 以前,若我們想要把某些功能傳遞給某些方...
閱讀 2857·2023-04-26 02:49
閱讀 3441·2021-11-25 09:43
閱讀 3370·2021-10-09 09:43
閱讀 2985·2021-09-28 09:44
閱讀 2446·2021-09-22 15:29
閱讀 4507·2021-09-14 18:02
閱讀 2773·2021-09-03 10:48
閱讀 3426·2019-08-30 12:47