初識Lambda表示式3----JDK提供函式式介面的引出2---java
寫在前面的話
總感覺上篇部落格有些東西需要補充,於是思來想去寫下了本篇部落格…
1.場景引入
場景: 假如有這樣一種場景,我們的專案裡有好多方法,這些方法的引數都包含一個介面,這些介面雖然其功能各不相同,但是卻都有一個共同點,就是它們輸入引數的個數和型別相同,返回結果的型別也相同.那具體開發中該如何去處理這種情況呢???
解決方式1: 很容易想到的一種解決方式就是我們先去定義這樣一個個的介面,再定義一個個的類去實現這些介面,然後將這些實現了指定介面的類作為引數傳遞給方法(多型),再去解決具體的問題.--------或者定義完介面後,不再去定義具體的類,而直接使用匿名內部類的方式,將所需要的介面引數傳遞給方法.這兩種解決辦法都可以算作比較傳統的方法,而且可以做到見名之義
package com.nrsc.lambda.FunctionInterfaceDemo;
//兩個數相加的介面
interface TwoNumberPlus {
int plus(int x, int y);
}
//兩個數相減的介面
interface TwoNumberMinus {
int minus(int x, int y);
}
class TwoNumberCalculateClass {
private int x;
private int y;
public TwoNumberCalculateClass(int x, int y) {
this.x = x;
this.y = y;
}
//兩個數相加
public int twoNumberPlus(TwoNumberPlus twoNumberPlus) {
return twoNumberPlus.plus(this.x, this.y);
}
//兩個數相減
public int twoNumberMinus(TwoNumberMinus twoNumberMinus) {
return twoNumberMinus.minus(this.x, this.y);
}
}
public class Demo1 {
public static void main(String[] args) {
TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);
//兩數相加
int res_plus = twoNumberCalculateClass.twoNumberPlus(new TwoNumberPlus() {
@Override
public int plus(int x, int y) {
return x + y;
}
});
System.out.println(res_plus); //15
//兩數相減
int res_minus = twoNumberCalculateClass.twoNumberMinus(new TwoNumberMinus() {
@Override
public int minus(int x, int y) {
return x - y;
}
});
System.out.println(res_minus); //-1
}
}
解決方式2.1: 當然還有一個看起來比較取巧的方法,那就是我們定義一個比較通用的介面,然後使用匿名內部類的方式,去完成我們的任務.栗子如下:
package com.nrsc.lambda.FunctionInterfaceDemo.demo1;
//兩個數之間進行計算的通用介面
interface TwoNumberCalculateInterface {
int calculate(int x, int y);
}
class TwoNumberCalculateClass {
private int x;
private int y;
public TwoNumberCalculateClass(int x, int y) {
this.x = x;
this.y = y;
}
//兩個數進行計算
public int twoNumberCalculate(TwoNumberCalculateInterface twoNumberCalculate) {
return twoNumberCalculate.calculate(this.x, this.y);
}
}
public class Demo1 {
public static void main(String[] args) {
TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);
//兩數相加
int res_plus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
@Override
public int calculate(int x, int y) {
return x + y;
}
});
System.out.println(res_plus); //15
//兩數相減
int res_minus = twoNumberCalculateClass.twoNumberCalculate(new TwoNumberCalculateInterface() {
@Override
public int calculate(int x, int y) {
return x - y;
}
});
System.out.println(res_minus); //-1
}
}
從上面的兩個栗子來看,方式2.1中的通用介面方式是可行的,但是在jdk8出來之前,應該很少有人會去這麼去做,為什麼呢?我想最主要的原因應該是,第二種方式其實並沒有比第一中方式省下來多少行程式碼(主要的程式碼量都在方法的重寫上),而且這樣還會讓程式碼做不到見名之義的效果.
比較有意思的一個地方
JDK8出來以後,我們發現2.1中所提到的這種通用介面卻直接成了JDK原始碼,而且還一下整出了40個(java.util.function包內的函式式介面). 我想這肯定與lambda表示式的簡潔,以及它真正關心的只是輸入引數和返回結果的特性相關(歸納一句就是可以使匿名內部類的方式更加簡潔). 舉個栗子:
package com.nrsc.lambda.FunctionInterfaceDemo;
import java.util.function.BinaryOperator;
class TwoNumberCalculateClass {
private int x;
private int y;
public TwoNumberCalculateClass(int x, int y) {
this.x = x;
this.y = y;
}
//使用JDK自帶的函式式介面
public int twoNumberCalculate1(BinaryOperator<Integer> binaryOperator) {
return binaryOperator.apply(this.x, this.y);
}
}
public class Demo1 {
public static void main(String[] args) {
TwoNumberCalculateClass twoNumberCalculateClass = new TwoNumberCalculateClass(7, 8);
/**
* 使用JDK自帶的函式式介面以及lambda表示式
*/
int res1 = twoNumberCalculateClass.twoNumberCalculate1((x, y) -> x + y);
System.out.println(res1); //15
/**
* 當然也可以使用原來的匿名內部類的方式----使用JDK自帶的函式式介面以及匿名內部類
*/
int res2 = twoNumberCalculateClass.twoNumberCalculate1(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
});
System.out.println(res2);
}
}
但是僅僅如此嗎?肯定不是!!!使用JDK自帶的函式式介面+lambda表示式雖然可以讓匿名內部類的方式大為簡化,但仍然會讓人感覺程式碼寫的不是那麼見名之義, 所以 JDK提供的函式式介面的出現肯定還有其他比較重要的作用 -----比如下篇部落格將會介紹到的方法引用.
接下來將介紹一下部分JDK提供的函式式介面的簡單使用方式,其實這些介面用起來都很簡單,大家嘗試著多寫寫應該就可以掌握,我做的幾個小栗子程式碼如下:
package com.nrsc.lambda.FunctionInterfaceDemo;
import java.text.DecimalFormat;
import java.util.function.*;
/**
* 部分JDK提供的函式式介面使用樣例
*/
public class Demo2 {
public static void main(String[] args) {
//斷言函式介面--- 接受一個引數,返回一個布林型別的結果
Predicate<Integer> fun1 = i -> i > 5;
System.out.println(fun1.test(4));
//JDK還提供了一些帶型別的函式式介面,用這些介面我們就不必再指定泛型了,如下:
IntPredicate fun11 = i -> i==10;
System.out.println(fun11.test(10));
//消費者----接受一個輸入引數並且無返回結果
Consumer fun2 = s -> System.out.println(s + " world");
fun2.accept("hello");
//提供者---無需輸入引數, 為我們提供或返回一個引數
Supplier<String> fun3 = () -> "hi , beijing";
System.out.println(fun3.get());
//Function<T,R>---輸入引數型別為T,返回型別為R的函式
Function<Integer, String> fun4 = i -> new DecimalFormat("#,###").format(i);
//一元函式-----接受一個引數為型別T,返回值型別也為T。
UnaryOperator<String> fun5 = s -> s.replace(",", "||");
System.out.println(fun5.apply("嘿嘿,哈哈"));
//BiFunction<T ,U ,R> 2個輸入的函式-----輸入型別為T和U,返回型別為R的函式
BiFunction<Integer, String, Boolean> fun6 = (i, s) -> (i + s).equals("111 hello world");
System.out.println(fun6.apply(111, " hello world"));
//BinaryOperator<T> 二元函式----需要輸入兩個引數,引數型別都為T,返回型別也為T的函式
BinaryOperator<Integer> fun7 = (s, t) -> s * t;
System.out.println(fun7.apply(7, 8));
}
}