Java8中Function函數式接口詳解及使用

1.函數式接口

函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。

Functional Interface(功能接口)爲lambda表達式和方法引用(用冒號::來進行方法的調用)提供目標類型。每個功能接口都有一個抽象方法,稱爲該功能接口的功能方法,lambda表達式的參數和返回類型與之匹配或適配。功能接口可以在多個上下文中提供目標類型,例如賦值上下文,方法調用或強制轉換上下文:

// Assignment context
Predicate<String> p = String::isEmpty;

// Method invocation context
stream.filter(e -> e.getSize() > 10)...

// Cast context
stream.map((ToIntFunction) e -> e.getSize())...

函數式接口可以使用lambda表達式,方法引用或構造函數引用創建功能接口的實例。

Java8爲函數式接口引入了一個新註解@FunctionalInterface,主要用於編譯級錯誤檢查,加上該註解,當接口不符合函數式接口定義的時候,編譯器會報錯。
此註解不是編譯器將接口識別爲功能接口的必要條件,而僅是幫助捕獲設計意圖並獲得編譯器幫助識別意外違反設計意圖的幫助。

正確例子,沒有報錯:

@FunctionalInterface
public interface HelloWorldService {

    void sayHello(String msg);

}

錯誤例子,接口中包含了兩個抽象方法,違反了函數式接口的定義,提示在接口中找到多個非重寫的抽象方法
函數式接口
注意: 加不加 @FunctionalInterface對於接口是不是函數式接口沒有影響,該註解只是提醒編譯器去檢查該接口是否僅包含一個抽象方法。

1.1允許定義默認方法

函數式接口裏是可以包含默認方法,因爲默認方法不是抽象方法,其有一個默認實現,所以是符合函數式接口的定義的。

如下代碼不會報錯:

@FunctionalInterface
public interface HelloWorldService {

    void sayHello(String msg);

    default void doSomeWork1() {
        // Method body
    }

    default void doSomeWork2() {
        // Method body
    }

}

1.2允許定義靜態方法

函數式接口裏是可以包含靜態方法,因爲靜態方法不能是抽象方法,是一個已經實現了的方法,所以是符合函數式接口的定義的。

如下代碼不會報錯:

@FunctionalInterface
public interface HelloWorldService {

    void sayHello(String msg);

    static void printHello() {
        System.out.println("Hello");
    }

}

1.3允許定義java.lang.Object的public方法

函數式接口裏是可以包含Object裏的public方法,這些方法對於函數式接口來說,不被當成是抽象方法(雖然它們是抽象方法);因爲任何一個函數式接口的實現,默認都繼承了Object類,包含了來自java.lang.Object裏對這些抽象方法的實現;

如下代碼不會報錯:

@FunctionalInterface
public interface HelloWorldService {

    void sayHello(String msg);

	@Override
    boolean equals(Object obj);

}

1.4已有函數式接口

函數式接口可以對現有的函數友好地支持lambda。

JDK1.8之前已有的函數式接口:

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

JDK1.8新增加的函數接口:

  • java.util.function

2.Function函數

序號 接口 描述
1 Function<T,R> 接收一個參數並返回結果的函數
2 BiFunction<T,U,R> 接受兩個參數並返回結果的函數
3 DoubleFunction<R> 接收一個double類型的參數並返回結果的函數
4 DoubleToIntFunction 接收一個double類型的參數並返回int結果的函數
5 DoubleToLongFunction 接收一個double類型的參數並返回long結果的函數
6 IntFunction<R> 接收一個int類型的參數並返回結果的函數
7 IntToDoubleFunction 接收一個int類型的參數並返回double結果的函數
8 IntToLongFunction 接收一個int類型的參數並返回long結果的函數
9 LongFunction<R> 接收一個long類型的參數並返回結果的函數
10 LongToDoubleFunction 接收一個long類型的參數並返回double結果的函數
11 LongToIntFunction 接收一個long類型的參數並返回int結果的函數
12 ToDoubleBiFunction<T,U> 接收兩個參數並返回double結果的函數
13 ToDoubleFunction<T> 接收一個參數並返回double結果的函數
14 ToIntBiFunction<T,U> 接收兩個參數並返回int結果的函數
15 ToIntFunction<T> 接收一個參數並返回int結果的函數
16 ToLongBiFunction<T,U> 接收兩個參數並返回long結果的函數
17 ToLongFunction<T> 接收一個參數並返回long結果的函數

2.1Function<T, R>

接口方法 方法描述
R apply(T t) 將此參數應用到函數中
Function<T, R> andThen(Function<? super R,? extends V> after) 返回一個組合函數,該函數結果應用到after函數中
Function<T, R> compose(Function<? super V,? extends T> before) 返回一個組合函數,首先將入參應用到before函數,再將before函數結果應用到該函數中

①apply(T t)

Function<String, String> function = a -> a + " Jack!";
System.out.println(function.apply("Hello")); // Hello Jack!

②andThen(Function<? super R,? extends V> after)

Function<String, String> function = a -> a + " Jack!";
Function<String, String> function1 = a -> a + " Bob!";
String greet = function.andThen(function1).apply("Hello");
System.out.println(greet); // Hello Jack! Bob!

③compose(Function<? super V,? extends T> before)

Function<String, String> function = a -> a + " Jack!";
Function<String, String> function1 = a -> a + " Bob!";
String greet = function.compose(function1).apply("Hello");
System.out.println(greet); // Hello Bob! Jack!

2.2BiFunction<T, U, R>

接口方法 方法描述
R apply(T t, U u) 將參數應用於函數執行
BiFunction<T,U,V> andThen(Function<? super R,? extends V> after) 返回一個組合函數,after函數應用於該函數之後

①apply(T t, U u)

BiFunction<String, String, String> biFunction = (a, b) -> a + b;
System.out.println(biFunction.apply("Hello ", "Jack!")); // Hello Jack!

②andThen(Function<? super R,? extends V> after)

BiFunction<String, String, String> biFunction = (a, b) -> a + b;
Function<String, String> function = (a) -> a + "!!!";
System.out.println(biFunction.andThen(function).apply("Hello", " Jack")); // Hello Jack!!!

2.3DoubleFunction

接口方法 方法描述
R apply(double value) 根據給定參數執行函數

①apply(double value)

DoubleFunction<String> doubleFunction = doub -> "結果:" + doub;
System.out.println(doubleFunction.apply(1.6)); // 結果:1.6

2.4DoubleToIntFunction

接口方法 方法描述
int applyAsInt(double value) 根據給定的參數執行函數

①applyAsInt(double value)

DoubleToIntFunction doubleToIntFunction = doub -> Double.valueOf(doub).intValue();
System.out.println(doubleToIntFunction.applyAsInt(1.2)); // 1

2.5ToDoubleBiFunction<T,U>

接口方法 方法描述
double applyAsDouble(T t, U u) 根據給定的參數執行函數

①applyAsDouble(T t, U u)

ToDoubleBiFunction<Long, Float> toDoubleBiFunction = (lon, floa) -> lon
	.doubleValue() + floa.doubleValue();
System.out.println(toDoubleBiFunction.applyAsDouble(11L, 235.5f)); // 246.5

2.6ToDoubleFunction

接口方法 方法描述
double applyAsDouble(T value) 根據給定參數執行函數

①applyAsDouble(T value)

ToDoubleFunction<Float> toDoubleFunction = floa -> floa.doubleValue();
System.out.println(toDoubleFunction.applyAsDouble(12315f)); // 12315.0

3.Consumer消費者

序號 接口 描述
1 Consumer<T> 提供一個T類型的輸入參數,不返回執行結果
2 BiConsumer<T,U> 提供兩個自定義類型的輸入參數,不返回執行結果
3 DoubleConsumer 表示接受單個double值參數,但不返回結果的操作
4 IntConsumer 表示接受單個int值參數,但不返回結果的操作
5 LongConsumer 表示接受單個long值參數,但不返回結果的操作
6 ObjDoubleConsumer<T> 表示接受object值和double值,但是不返回任何操作結果
7 ObjIntConsumer<T> 表示接受object值和int值,但是不返回任何操作結果
8 ObjLongConsumer<T> 表示接受object值和long值,但是不返回任何操作結果

3.1Consumer<T>

接口方法 方法描述
void accept(T t) 對給定的參數執行操作
default Consumer andThen(Consumer<? super T> after) 返回一個組合函數,after將會在該函數執行之後應用

①accept(T t)

StringBuilder sb = new StringBuilder("Hello ");
Consumer<StringBuilder> consumer = (str) -> str.append("Jack!");
consumer.accept(sb);
System.out.println(sb.toString());	// Hello Jack!

②andThen(Consumer<? super T> after)

StringBuilder sb = new StringBuilder("Hello ");
Consumer<StringBuilder> consumer = (str) -> str.append("Jack!");
Consumer<StringBuilder> consumer1 = (str) -> str.append(" Bob!");
consumer.andThen(consumer1).accept(sb);
System.out.println(sb.toString());	// Hello Jack! Bob!

3.2BiConsumer<T,U>

接口方法 方法描述
void accept(T t, U u) 對給定的參數執行操作
default BiConsumer<T,U> andThen(BiConsumer<? super T,? super U> after) 返回一個組合函數,after將會在該函數執行之後應用

①accept(T t, U u)

StringBuilder sb = new StringBuilder();
BiConsumer<String, String> biConsumer = (a, b) -> {
	sb.append(a);
	sb.append(b);
};
biConsumer.accept("Hello ", "Jack!");
System.out.println(sb.toString());	// Hello Jack!

②andThen(BiConsumer<? super T,? super U> after)

StringBuilder sb = new StringBuilder();
BiConsumer<String, String> biConsumer = (a, b) -> {
	sb.append(a);
	sb.append(b);
};
BiConsumer<String, String> biConsumer1 = (a, b) -> {
	System.out.println(a + b);
};
biConsumer.andThen(biConsumer1).accept("Hello", " Jack!"); // Hello Jack!

3.3DoubleConsumer

接口方法 方法描述
void accept(double value) 對給定的參數執行操作
default DoubleConsumer andThen(DoubleConsumer after) 返回一個組合函數,after在該函數執行之後應用

①accept(double value)

DoubleConsumer doubleConsumer = System.out::println;
doubleConsumer.accept(1.3); // 1.3

②andThen(DoubleConsumer after)

DoubleConsumer doubleConsumer = System.out::println;
DoubleConsumer doubleConsumer1 = System.out::println;
doubleConsumer.andThen(doubleConsumer1).accept(1.3);
// 1.3  
// 1.3

3.4ObjDoubleConsumer<T>

接口方法 方法描述
void accept(T t, double value) 對給定的參數執行操作

①accept(T t, double value)

ObjDoubleConsumer<String> doubleConsumer = (obj, doub)
	-> System.out.println(obj + doub);
doubleConsumer.accept("金額:", 222.66); // 金額:222.66

4.Predicate謂語

序號 接口 描述
1 Predicate<T> 對給定的輸入參數執行操作,返回一個boolean類型的結果(布爾值函數)
2 BiPredicate<T,U> 對給定的兩個輸入參數執行操作,返回一個boolean類型的結果(布爾值函數)
3 DoublePredicate 對給定的double參數執行操作,返回一個boolean類型的結果(布爾值函數)
4 IntPredicate 對給定的int輸入參數執行操作,返回一個boolean類型的結果(布爾值函數)
5 LongPredicate 對給定的long參數執行操作,返回一個boolean類型的結果(布爾值函數)

4.1Predicate<T>

接口方法 方法描述
boolean test(T t) 根據給定的參數進行判斷
Predicate and(Predicate<? super T> other) 返回一個組合判斷,將other以短路與的方式加入到函數的判斷中
Predicate or(Predicate<? super T> other) 返回一個組合判斷,將other以短路或的方式加入到函數的判斷中
Predicate negate() 將函數的判斷取反

①test(T t)

Predicate<Integer> predicate = number -> number != 0;
System.out.println(predicate.test(10));    //true

②and(Predicate<? super T> other)

Predicate<Integer> predicate = number -> number != 0;
predicate = predicate.and(number -> number >= 10);
System.out.println(predicate.test(10));    //true

③or(Predicate<? super T> other)

Predicate<Integer> predicate = number -> number != 0;
predicate = predicate.or(number -> number != 10);
System.out.println(predicate.test(10));    //true

④negate()

Predicate<Integer> predicate = number -> number != 0;
predicate = predicate.negate();
System.out.println(predicate.test(10));    //false

4.2BiPredicate<T,U>

接口方法 方法描述
boolean test(T t, U u) 根據給定的兩個輸入參數進行判斷
BiPredicate<T,U> and(BiPredicate<? super T,? super U> other) 返回一個組合判斷,將other以短路與的方式加入到函數的判斷中
BiPredicate<T,U> or(BiPredicate<? super T,? super U> other) 返回一個組合判斷,將other以短路或的方式加入到函數的判斷中
BiPredicate<T,U> negate() 將函數的判斷取反

①test(T t, U u)

BiPredicate<Integer, Integer> biPredicate = (a, b) -> a != b;
System.out.println(biPredicate.test(1, 2)); // true

②and(BiPredicate<? super T,? super U> other)

BiPredicate<Integer, Integer> biPredicate = (a, b) -> a != b;
biPredicate = biPredicate.and((a, b) -> a.equals(b));
System.out.println(biPredicate.test(1, 2)); // false

③or(BiPredicate<? super T,? super U> other)

BiPredicate<Integer, Integer> biPredicate = (a, b) -> a != b;
biPredicate = biPredicate.or((a, b) -> a == b);
System.out.println(biPredicate.test(1, 1)); // true

④negate()

BiPredicate<Integer, Integer> biPredicate = (a, b) -> a != b;
biPredicate = biPredicate.negate();
System.out.println(biPredicate.test(1, 2)); // false

4.3DoublePredicate

接口方法 方法描述
boolean test(double value) 根據給定的參數進行判斷
DoublePredicate and(DoublePredicate other) 返回一個組合判斷,將other以短路與的方式加入到函數的判斷中
DoublePredicate or(DoublePredicate other) 返回一個組合判斷,將other以短路或的方式加入到函數的判斷中
default DoublePredicate negate() 將函數的判斷取反

①test(double value)

DoublePredicate doublePredicate = doub -> doub != 0;
System.out.println(doublePredicate.test(10)); // true

②and(DoublePredicate other)

DoublePredicate doublePredicate = doub -> doub != 0;
doublePredicate = doublePredicate.and(doub -> doub < 2);
System.out.println(doublePredicate.test(1.7)); // true

③or(DoublePredicate other)

DoublePredicate doublePredicate = doub -> doub != 0;
doublePredicate = doublePredicate.or(doub -> doub > 2);
System.out.println(doublePredicate.test(1.7)); // true

④negate()

DoublePredicate doublePredicate = doub -> doub != 0;
doublePredicate = doublePredicate.negate();
System.out.println(doublePredicate.test(1.7)); // false

5.Supplier供應商

序號 接口 描述
1 Supplier<T> 不提供輸入參數,但是返回結果的函數
2 BooleanSupplier 不提供輸入參數,但是返回boolean結果的函數
3 DoubleSupplier 不提供輸入參數,但是返回double結果的函數
4 IntSupplier 不提供輸入參數,但是返回int結果的函數
5 LongSupplier 不提供輸入參數,但是返回long結果的函數

5.1Supplier<T>

接口方法 方法描述
T get() 獲取結果值

①get()

Supplier<String> supplier = () -> "Hello Jack!";
System.out.println(supplier.get()); // Hello Jack!

5.2BooleanSupplier

接口方法 方法描述
boolean getAsBoolean() 獲取函數的執行結果

①getAsBoolean()

BooleanSupplier booleanSupplier = () -> true;
System.out.println(booleanSupplier.getAsBoolean()); // true

5.3DoubleSupplier

接口方法 方法描述
double getAsDouble() 獲取函數的執行結果

①getAsDouble()

DoubleSupplier doubleSupplier = () -> 2.7;
System.out.println(doubleSupplier.getAsDouble()); // 2.7

6.Operator操作員

除了Function,Consumer,Predicate,Supplier這幾個基本的函數形式,還有其它派生的函數形式,它們擴展了基本的函數形式,包括UnaryOperator (extends Function)和BinaryOperator (extends BiFunction)。

序號 接口 描述
1 UnaryOperator<T> 提供單個類型參數,並且返回一個與輸入參數類型一致的結果
2 BinaryOperator<T> 提供兩個相同類型參數,並且返回結果與輸入參數類型一致的結果
3 DoubleBinaryOperator 提供兩個double參數並且返回double結果
4 DoubleUnaryOperator 提供單個double參數並且返回double結果
5 IntBinaryOperator 提供兩個int參數並且返回int結果
6 IntUnaryOperator 提供單個int參數並且返回int結果
7 LongBinaryOperator 提供兩個long參數並且返回long結果
8 LongUnaryOperator 提供單個long參數並且返回long結果

6.1UnaryOperator<T>

接口方法 方法描述
T apply(T t) 將給定參數應用到函數中
Function<T, R> andThen(Function<? super R,? extends V> after) 返回一個組合函數,該函數結果應用到after函數中
Function<T, R> compose(Function<? super V,? extends T> before) 返回一個組合函數,首先將入參應用到before函數,再將before函數結果應用到該函數中

①apply(T t)

UnaryOperator<String> unaryOperator = greet -> greet + " Bob!";
System.out.println(unaryOperator.apply("Hello")); // Hello Bob!

②andThen(Function<? super T,? extends T> after)

UnaryOperator<String> unaryOperator = greet -> greet + " Bob!";
UnaryOperator<String> unaryOperator1 = greet -> greet + " Jack!";
String greet = unaryOperator.andThen(unaryOperator1).apply("Hello");
System.out.println(greet); // Hello Bob! Jack!

③compose(Function<? super T,? extends T> before)

UnaryOperator<String> unaryOperator = greet -> greet + " Bob!";
UnaryOperator<String> unaryOperator1 = greet -> greet + " Jack!";
String greet = unaryOperator.compose(unaryOperator1).apply("Hello");
System.out.println(greet); // Hello Jack! Bob!

6.2BinaryOperator<T>

接口方法 方法描述
T apply(T t, T u) 根據給定參數執行函數
BiFunction<T,T,T> andThen(Function<? super T,? extends T> after) 返回一個組合函數,after應用於該函數之後
BinaryOperator maxBy(Comparator<? super T> comparator) 返回二元操作本身,通過特殊比較器返回最大的元素
BinaryOperator minBy(Comparator<? super T> comparator) 返回二元操作本身,通過特殊比較器返回最小的元素

①apply(T t, T u)

BinaryOperator<String> binaryOperator = (flag, flag1) -> flag + flag1;
System.out.println(binaryOperator.apply("Hello ", "Jack!")); // Hello Jack!

②andThen(Function<? super T,? extends T> after)

BinaryOperator<String> binaryOperator = (flag, flag1) -> flag + flag1;
Function<String, String> function = a -> a + "!!!";
System.out.println(binaryOperator.andThen(function).apply("Hello", " Jack")); // Hello Jack!!!

③maxBy(Comparator<? super T> comparator)

BinaryOperator<Integer> integerBinaryOperator = BinaryOperator.maxBy(Integer::compareTo);
Integer max = integerBinaryOperator.apply(12, 10);
System.out.println(max); // 12

④minBy(Comparator<? super T> comparator)

BinaryOperator<Integer> integerBinaryOperator1 = BinaryOperator.minBy(Integer::compare);
Integer min = integerBinaryOperator1.apply(12, 10);
System.out.println(min); // 10

6.3DoubleBinaryOperator

接口方法 方法描述
double applyAsDouble(double left, double right) 根據給定的參數執行函數

①applyAsDouble(double left, double right)

DoubleBinaryOperator doubleBinaryOperator = (doub1, doub2) -> doub1
	+ doub2;
System.out.println(doubleBinaryOperator.applyAsDouble(1.1, 2.3)); // 3.4

6.4DoubleUnaryOperator

接口方法 方法描述
double applyAsDouble(double operand) 根據給定參數執行函數
DoubleUnaryOperator andThen(DoubleUnaryOperator after) 返回一個組合函數,after應用於該函數之後
DoubleUnaryOperator compose(DoubleUnaryOperator before) 返回一個組合函數,before應用於該函數之前

①applyAsDouble(double operand)

DoubleUnaryOperator doubleUnaryOperator = doub -> doub + 2.5;
System.out.println(doubleUnaryOperator.applyAsDouble(2.6)); // 5.1

②andThen(DoubleUnaryOperator after)

DoubleUnaryOperator doubleUnaryOperator = doub -> doub + 2.5;
DoubleUnaryOperator doubleUnaryOperator1 = doub -> doub * 3;
double result = doubleUnaryOperator.andThen(doubleUnaryOperator1)
	.applyAsDouble(10); 
System.out.println(result); // (10 + 2.5) * 3 = 37.5

③compose(DoubleUnaryOperator before)

DoubleUnaryOperator doubleUnaryOperator = doub -> doub + 2.5;
DoubleUnaryOperator doubleUnaryOperator1 = doub -> doub * 3;
double result = doubleUnaryOperator.compose(doubleUnaryOperator1)
	.applyAsDouble(10);
System.out.println(result); // 10 * 3 + 2.5 = 32.5

本文參考:
Java 8 新特性-Function函數式接口
Java 8 函數式接口
https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html#package.description

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章