Java 8方法引用使用指南
【編者按】本文作者為擁有15年 Java 開發經驗的資深程式設計師 Per-Åke Minborg,主要介紹如何靈活地解析 Java 中的方法引用。文章系國內 ITOM 管理平臺 OneAPM 編譯呈現。
方法引用
眾所周知,在Java 8中我們可以使用方法引用。譬如,在我們需要遍歷流元素時,可以使用 String::isEmpty
來引用isEmpty
方法。試看下面這段程式碼:
Stream.of("A", "", "B").filter(Stream::isEmpty).count();
執行的結果為1(因為在這個流中只有一個空元素)。但是,如果我們要過濾出非空字串,我們得寫成.filter(s -> !s.isEmpty())
。這是一個Lambda表示式。顯然,這兒有個討厭的不對稱想象。我們可以使用方法引用,但卻不能用它的反式。我們可以寫predicate.negate()
卻不能寫Stream::isEmpty.negate()
或!Stream::isEmpty
。
為什麼呢?這是因為方法引用並非Lambda表示式或者函式介面。不過,使用Java的型別推導可以將方法引用解析為一個或多個函式介面。上例中的String::isEmpty
至少可以解析為:
Predicate<String>
Function<String, Boolean>
所以,我們要排除其他可能性,確定到底將方法引用轉換為哪個函式介面。本文在一定程度上解決了該問題。文中的程式碼來自開源專案Speedment,它讓資料庫看起來像Java 8的流。
解析方法引用
其實,以靜態方法為“管道”,可以部分地解決這個問題——該靜態方法以一個方法引用為輸入,以特定的函式介面為其返回。試考慮下面這個簡短的靜態方法:
public static <T> Predicate<T> as(Predicate<T> predicate) {
return predicate;
}
現在,如果靜態地匯入這個方法,事實上,我們就能更簡單地使用方法引用。如下例所示:
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();
這段程式碼返回的結果為2,即流中非空元素的數量。有關方法引用的使用方式,我們又向前邁進了一步。另一個好處是,這個解決方案讓我們更輕鬆地編寫predicates介面,例如:
.filter(as(String::isEmpty).negate().and("A"::equals))
解析所有方法引用
但是,現在仍有一個問題亟待解決。我們不能隨隨便便地建立一大堆靜態as()
函式,因為一個方法引用可能解析為多種as()
方法,正如本文開頭提到的那樣。所以,一個更妙的解決方案,是把函式介面型別名新增至每個靜態方法,這樣我們就可以程式化地為每個函式介面轉換方法選擇一個特定的方法引用。我們有一個工具類,可以讓每個方法引用都轉換為Java標準包 `java.util.function中任意匹配的函式介面。
直接在GitHub下載最新版本
import java.util.function.*;
/**
*
* @author Per Minborg
*/
public class FunctionCastUtil {
public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) {
return biConsumer;
}
public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) {
return biFunction;
}
public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) {
return binaryOperator;
}
public static <T, U> BiPredicate<T, U> asBiPredicate(BiPredicate<T, U> biPredicate) {
return biPredicate;
}
public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) {
return booleanSupplier;
}
public static <T> Consumer<T> asConsumer(Consumer<T> consumer) {
return consumer;
}
public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) {
return doubleBinaryOperator;
}
public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) {
return doubleConsumer;
}
public static <R> DoubleFunction<R> asDoubleFunction(DoubleFunction<R> 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 <T, R> Function<T, R> asFunction(Function<T, R> function) {
return function;
}
public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) {
return intBinaryOperator;
}
public static IntConsumer asIntConsumer(IntConsumer intConsumer) {
return intConsumer;
}
public static <R> IntFunction<R> asIntFunction(IntFunction<R> 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 <R> LongFunction<R> asLongFunction(LongFunction<R> longFunction) {
return longFunction;
}
public static LongPredicate asLongPredicate(LongPredicate longPredicate) {
return longPredicate;
}
public static <T> 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 <T> ObjDoubleConsumer<T> asObjDoubleConsumer(ObjDoubleConsumer<T> objDoubleConsumer) {
return objDoubleConsumer;
}
public static <T> ObjIntConsumer<T> asObjIntConsumer(ObjIntConsumer<T> objIntConsumer) {
return objIntConsumer;
}
public static <T> ObjLongConsumer<T> asObjLongConsumer(ObjLongConsumer<T> objLongConsumer) {
return objLongConsumer;
}
public static <T> Predicate<T> asPredicate(Predicate<T> predicate) {
return predicate;
}
public static <T> Supplier<T> asSupplier(Supplier<T> supplier) {
return supplier;
}
public static <T, U> ToDoubleBiFunction<T, U> asToDoubleBiFunction(ToDoubleBiFunction<T, U> toDoubleBiFunction) {
return toDoubleBiFunction;
}
public static <T> ToDoubleFunction<T> asToDoubleFunction(ToDoubleFunction<T> toDoubleFunction) {
return toDoubleFunction;
}
public static <T, U> ToIntBiFunction<T, U> asToIntBiFunction(ToIntBiFunction<T, U> toIntBiFunction) {
return toIntBiFunction;
}
public static <T> ToIntFunction<T> asToIntFunction(ToIntFunction<T> ioIntFunction) {
return ioIntFunction;
}
public static <T, U> ToLongBiFunction<T, U> asToLongBiFunction(ToLongBiFunction<T, U> toLongBiFunction) {
return toLongBiFunction;
}
public static <T> ToLongFunction<T> asToLongFunction(ToLongFunction<T> toLongFunction) {
return toLongFunction;
}
public static <T> UnaryOperator<T> asUnaryOperator(UnaryOperator<T> unaryOperator) {
return unaryOperator;
}
private FunctionCastUtil() {
}
}
在靜態匯入了相關方法之後,我們就可以這樣寫:
Stream.of("A", "", "B").filter(asPredicate(String::isEmpty).negate()).count();
一個更好的解決方案
如果函式介面本身就包含一個接收方法引用並將其轉換為某類函式介面的靜態方法,那就更好了。舉例來說,標準的Java Predicated
函式介面就會變成這樣:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {...}
default Predicate<T> negate() {...}
default Predicate<T> or(Predicate<? super T> other) {...}
static <T> Predicate<T> isEqual(Object targetRef) {...}
// New proposed support method to return a
// Predicate view of a Functional Reference
public static <T> Predicate<T> of(Predicate<T> predicate) {
return predicate;
}
}
因此,我們可以這樣寫:
Stream.of("A", "", "B").filter(Predicate.of(String::isEmpty).negate()).count();
筆者覺得這樣看起來好極了!
快聯絡離你最近的Open JDK開發人員,提出你的修改建議吧!
OneAPM 能為您提供端到端的 Java 應用效能解決方案,我們支援所有常見的 Java 框架及應用伺服器,助您快速發現系統瓶頸,定位異常根本原因。分鐘級部署,即刻體驗,Java 監控從來沒有如此簡單。想閱讀更多技術文章,請訪問 OneAPM 官方技術部落格。
本文轉自 OneAPM 官方部落格
原帖地址:https://dzone.com/articles/put-your-java-8-method-references-to-work
相關文章
- Java8——方法引用Java
- java8(二)方法引用Java
- Java 8 新特性之方法引用Java
- java8 新特性之方法引用Java
- 使用java8的方法引用替換硬編碼Java
- Java8 Stream完全使用指南Java
- java8的新特性之lambda表示式和方法引用Java
- Java筆記:方法引用Java筆記
- Java 中的方法引用Java
- Java 8中的Stream API使用指南JavaAPI
- Java中的方法引用詳解Java
- Java 8 中的方法引用,輕鬆減少程式碼量,提升可讀性!Java
- Java開發筆記(六十四)靜態方法引用和例項方法引用Java筆記
- Java中方法引用與Lambda區別 - foojayJava
- Java 不可變集合 Stream流以及方法引用Java
- 方法引用
- Java的強引用、軟引用、弱引用、虛引用Java
- Java8 常用方法Java
- Java四種引用包括強引用,軟引用,弱引用,虛引用。Java
- Java Optional使用指南Java
- ?Java8新特性之Lambda表示式,函式式介面,方法引用和default關鍵字Java函式
- 理解Java的強引用、軟引用、弱引用和虛引用Java
- Java8 預設方法Java
- java 8裡 Method方法bugJava
- java的強引用、軟引用、弱引用、幻象引用,引用佇列總結Java佇列
- Java四大引用詳解:強引用、軟引用、弱引用、虛引用Java
- Java中的四種引用方式(強引用、軟引用、弱引用、虛引用)Java
- Java/Android中的強引用、軟引用、弱引用、虛引用JavaAndroid
- Java常見知識點彙總(⑲)——Java中的強引用、弱引用、軟引用、虛引用Java
- Java-基礎語法20:Lambda&方法引用Java
- Java BigDecimal使用指南JavaDecimal
- Java 中 MongoDB 使用指南JavaMongoDB
- Java引用型別解析:掌握強引用、軟引用、弱引用和幻象引用的妙用Java型別
- java8新特性之函式式介面、lambda表示式、介面的預設方法、方法和建構函式的引用Java函式
- java方法中只有值傳遞,沒有引用傳遞Java
- Java中的引用Java
- java日誌列印使用指南Java
- java修飾符使用指南Java