日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

1. 簡介

JAVA8 引入了函數式編程,可以把函數作為參數傳入實現通用方法。熟知的 Java 8 單個參數函數式接口比如 Function、Predicate 和 Consumer。

這篇教程會介紹如何使用支持兩個參數的函數式接口。這樣的函數被稱為二元函數,在 Java 中使用 BiFunction 函數式接口。

2. 單個參數函數

讓我們快速回顧一下如何使用單個參數函數或者一元函數,就像在Stream教程中實現的示例:

List<String> mApped = Stream.of("hello", "world")
 .map(word -> word + "!")
 .collect(Collectors.toList());
assertThat(mapped).containsExactly("hello!", "world!");

 

上面的單元測試中,map 方法接受1個 Function 類型作為參數,對給定的的輸入操作后返回結果。

3. 雙參操作

Java Stream 庫提供了 reduce 函數,可以組合 Stream 中的元素。在這里定義已接收的數據如何與下一個操作轉換。

reduce 接受 BinaryOperator<T> 類型作為參數,支持輸入兩個類型相同的對象。

假設要求把 Stream 中的數據通過破折號連接起來,下面是幾種實現方案。

3.1. 使用 Lambda 表達式

用 Lambda 實現 BiFunction,前面是由括號包圍的兩個參數:

String result = Stream.of("hello", "world")
 .reduce("", (a, b) -> b + "-" + a);
assertThat(result).isEqualTo("world-hello-");

 

上面的示例中,a、b 兩個值是字符串類型。Lambda 實現把兩個參數按照要求組合,b 在前,a 在后,中間是破折號。

可以看到 reduce 的第一個參數是空字符串,Stream 中的第一個值會與空字符串連接。

另外可以注意到,Java 類型推斷在大多數情況下可以忽略參數類型。在 Lambda 上下文類型不明確的情況下,可以為參數加上類型:

String result = Stream.of("hello", "world")
 .reduce("", (String a, String b) -> b + "-" + a);

 

3.2. 使用 Function

如果上面的算法要求不在結尾加上破折號該怎么處理?可以在 lambda 中編寫更多代碼,但這可能會讓代碼變得更雜亂??梢园阉槿〕梢粋€函數:

private String combineWithoutTrailingDash(String a, String b) {
 if (a.isEmpty()) {
 return b;
 }
 return b + "-" + a;
}

 

然后調用:

String result = Stream.of("hello", "world")
 .reduce("", (a, b) -> combineWithoutTrailingDash(a, b));
assertThat(result).isEqualTo("world-hello");

 

像上面這樣,lambda 會調用抽取出來的函數。不僅更易于閱讀,而且可以擴充到更復雜的實現。

3.3. 使用方法引用

一些 IDE 會自動提示,把面的 lambda 轉換為方法引用,這樣讀起來會更清晰。

重寫上面的代碼,改為方法引用:

String result = Stream.of("hello", "world")
 .reduce("", this::combineWithoutTrailingDash);
assertThat(result).isEqualTo("world-hello");

 

方法引用通常讓函數式代碼自解釋性變得更強。

4. 使用 BiFunction

到目前為止,我們介紹了如何對兩個相同類型的參數使用函數。BiFunction 接口支持不同參數的類型 且返回值可以是第三種類型。

假設要求把兩個長度相等的列表合并成一個結果列表,對每對輸入值執行操作計算結果:

List<String> list1 = Arrays.asList("a", "b", "c");
List<Integer> list2 = Arrays.asList(1, 2, 3);
List<String> result = new ArrayList<>();
for (int i=0; i < list1.size(); i++) {
 result.add(list1.get(i) + list2.get(i));
}
assertThat(result).containsExactly("a1", "b2", "c3");

 

4.1. 為 Function 增加范型

可以使用 BiFunction 為方法增加范型 combiner

private static <T, U, R> List<R> listCombiner(
 List<T> list1, List<U> list2, BiFunction<T, U, R> combiner) {
 List<R> result = new ArrayList<>();
 for (int i = 0; i < list1.size(); i++) {
 result.add(combiner.apply(list1.get(i), list2.get(i)));
 }
 return result;
}

 

上面的代碼包含了三種參數類型:第一個列表中的元素類型為 T,第二個列表中的元素類型為 U,組合函數調用后的元素類型為 R。

調用 BiFunction 的 apply 方法 得到結果。

4.2. 調用范型函數

combiner 的類型是 BiFunction,設計的算法可以處理不同類型的輸入和輸出。讓我們試一下:

List<String> list1 = Arrays.asList("a", "b", "c");
List<Integer> list2 = Arrays.asList(1, 2, 3);
List<String> result = listCombiner(list1, list2, (a, b) -> a + b);
assertThat(result).containsExactly("a1", "b2", "c3");

 

也可以用來處理完全不同類型的輸入和輸出。

讓我們加入一個算法,判斷列表1中的值是否大于列表2,并生成一個 boolean 結果:

List<Double> list1 = Arrays.asList(1.0d, 2.1d, 3.3d);
List<Float> list2 = Arrays.asList(0.1f, 0.2f, 4f);
List<Boolean> result = listCombiner(list1, list2, (a, b) -> a > b);
assertThat(result).containsExactly(true, true, false);

 

4.3. BiFunction 方法引用

用上面抽取的方法和方法引用重寫上面的代碼:

List<Double> list1 = Arrays.asList(1.0d, 2.1d, 3.3d);
List<Float> list2 = Arrays.asList(0.1f, 0.2f, 4f);
List<Boolean> result = listCombiner(list1, list2, this::firstIsGreaterThanSecond);
assertThat(result).containsExactly(true, true, false);
private boolean firstIsGreaterThanSecond(Double a, Float b) {
 return a > b;
}

 

用方法引用加入算法 firstIsGreaterThanSecond 看起來代碼更容易理解一些。

4.4. 使用 this 調用 BiFunction 方法引用

改變一下要求,用上面基于 BiFunction 算法確認兩個列表是否相等:

List<Float> list1 = Arrays.asList(0.1f, 0.2f, 4f);
List<Float> list2 = Arrays.asList(0.1f, 0.2f, 4f);
List<Boolean> result = listCombiner(list1, list2, (a, b) -> a.equals(b));
assertThat(result).containsExactly(true, true, true);

 

實際上可以簡化成下面這樣:

List<Boolean> result = listCombiner(list1, list2, Float::equals);

 

這是因為 Float 中的 equals 與 BiFunction 函數簽名相同,第一個隱式參數是 Float 類型,第二個參數是 Object 類型與第一個參數比值。

5. BiFunctions 組合

如果通過方法引用實現數值比較該怎么實現?

如果使用方法引用實現數值列表比較示例會是怎樣?

List<Double> list1 = Arrays.asList(1.0d, 2.1d, 3.3d);
List<Double> list2 = Arrays.asList(0.1d, 0.2d, 4d);
List<Integer> result = listCombiner(list1, list2, Double::compareTo);
assertThat(result).containsExactly(1, 1, -1);

 

這個例子與之前的很像,但是返回值類型為 Integer 而非原來的 Boolean。這是因為 Double 中的 compareTo 方法返回類型為 Integer。

這里可以使用 andThen 在原來的基礎上增加額外的處理。這會生成 BiFunction,先對兩個輸入執行操作,然后接著執行另一個操作。

接下來,新建一個函數來把 Double::compareTo 方法引用強制轉換為 BiFunction:

private static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> function) {
 return function;
}

 

lambda 或者方法引用只在轉換后才能變成 BiFunction??梢允褂孟旅?helper 函數把 lambda 顯示轉換為 BiFunction 對象。

現在,使用 andThen 擴展現有函數的行為:

List<Double> list1 = Arrays.asList(1.0d, 2.1d, 3.3d);
List<Double> list2 = Arrays.asList(0.1d, 0.2d, 4d);
List<Boolean> result = listCombiner(list1, list2,
 asBiFunction(Double::compareTo).andThen(i -> i > 0));
assertThat(result).containsExactly(true, true, false);
Java BiFunction 接口實例

6. 總結

本文從 Java Stream 庫與自定義函數兩個角度探索了 BiFunction 和 BinaryOperator 的用法,了解了如何使用 lambda 和方法引用傳遞 BiFunction 以及組合函數。

Java 庫只提供單個參數和兩個參數的函數式接口。需要更多參數,請參閱柯里化獲得更多想法。完整的源代碼可以在 GitHub 上找到。

分享到:
標簽:接口 Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定