方法參考 眾所周知,我們可以使用Java 8中的方法引用 (例如String::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 Streams。 隨意嘗試Speedment out。
Speedment還包含謂詞生成器,使您可以直接使用諸如Entity.NAME::isEmpty和Entity.NAME::isNotEmpty之類的函數。
解析方法參考 通過以靜態方法的形式引入一些“管道”,可以部分解決該問題,該方法采用“方法參考”并將其作為特定功能接口的視圖返回。 考慮以下簡短的靜態方法:
public static <T> Predicate<T> as(Predicate<T> predicate) {return predicate;}
現在,如果我們靜態導入該方法,實際上,我們可以更輕松地使用“方法引用”,如以下簡短示例所示:
Stream.of("A", "", "B").filter(as(String::isEmpty).negate()).count();
該代碼將返回2,這是流中非空元素的數量。 在方法參考用法方面,這是向前邁出的一步。 另一個好處是,此解決方案使我們可以更輕松地組成謂詞,如下所示:
.filter(as(String::isEmpty).negate().and("A"::equals))
解決所有方法參考 但是,我們仍然需要解決一個問題。 我們不能簡單地開始創建很多靜態的as()函數,因為方法引用可能可以用本文開頭列出的相同方式解析為幾種潛在的as()方法。 因此,更好的方法是將功能接口類型名稱附加到每個靜態方法,從而使我們能夠以編程方式選擇特定的方法參考到功能接口轉換方法。 這是一個實用程序類,它允許將方法引用轉換為駐留在標準Java包java.util.function中的任何匹配的Functional Interface。
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 Predicate功能接口將如下所示:
@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開發人員聯系并提出建議!
翻譯自: https://www.javacodegeeks.com/2016/03/put-java-8-method-references-work.html
總結
以上是生活随笔 為你收集整理的使您的Java 8方法引用生效 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。