1. 程式人生 > >Java 8 中的方法引用

Java 8 中的方法引用

時間 情況 arrays 抽象 以及 eth ted 方式 消費

一、原理概要

lambda 表示式,可以作為某些匿名內部類的替代。主要目的是調用該內部類中的方法,而該方法的實現(重寫)由 lambda表示式決定。

通常,我們可能不關心匿名內部類中的具體方法(被重寫的方法),而只關心該方法是怎麽被重寫的(方法的實現)。因此,我們可以構造一個中間對象(通常是接口,比如 Funtion),該接口擁有一個需要該重寫的方法(比如 Function 對應的方法是 apply)。

二、如何使用

在實際書寫時,可以只寫出(傳遞的參數)與{方法的實現},或者只標出實現過程的 調用者的和其方法名(使用冒號分隔)。

Function<Person, Integer> getAge = Person::getAge;
// 傳參數調用 getAge 方法
Integer age = getAge.apply(p);

註釋:

1. 比如 Function<T,R>T 表示傳入類型,R 表示返回類型。比如,表達式 person -> person.getAge();,傳入參數是 person,返回值是 person.getAge(),那麽方法引用 Person::getAge 就對應著 Function<Person,Integer> 類型。

2. 使用雙冒號的方式會返回這個對象,當你調用該對象中的 apply 方法時,就會調用你之前傳進去的方法。

3. 這個過程類似一個函數的閉包。當你使用雙冒號的方式,會把你的類和方法傳入並生成一個 Function對象。該對象會在之後某個時間被調用,此時它會調用之前你傳入這個對象中的方法。

4. 三種方式對比

// old way
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for (Integer n : list) {
    System.out.println(n);
}

// 使用 -> 的 Lambda 表達式
list.forEach(n -> System.out.println(n));

// 使用 :: 的 Lambda 表達式
list.forEach(System.out::println);

  

三、關於函數式接口

1. Java 8中允許接口實現方法, 而不是簡單的聲明。需要使用關鍵字 default

2. Java8 中的 函數式接口中除了定義抽象方法外還可以包含靜態方法。

@FunctionalInterface
interface FunctionalInterfaceWithStaticMethod {
	static int sum(int[] array) {
		return Arrays.stream(array).reduce((a, b) -> a+b).getAsInt();
	}
	
	void apply();
}

註. @FunctionalInterface註解,主要用於編譯級錯誤檢查,加上該註解,當你寫的接口不符合函數式接口定義的時候,編譯器會報錯。 

 

3.一般情況下函數式接口只會定義一個抽象方法,但是接口最終有確定的類實現, 而類的最終父類是Object。 因此函數式接口可以定義Object 中的public方法,protected 方法不行。

@FunctionalInterface
public interface ObjectMethodFunctionalInterface {
	void count(int i);
	
	String toString(); //same to Object.toString
	int hashCode(); //same to Object.hashCode
	boolean equals(Object obj); //same to Object.equals
}

  

4. util 包中的函數式接口

java.util.function中定義了幾組類型的函數式接口以及針對基本數據類型的子接口。

  • Predicate -- 傳入一個參數,返回一個bool結果, 方法為boolean test(T t)
  • Consumer -- 傳入一個參數,無返回值,純消費。 方法為void accept(T t)
  • Function<t,r> -- 傳入一個參數,返回一個結果,方法為R apply(T t)
  • Supplier -- 無參數傳入,返回一個結果,方法為T get()
  • UnaryOperator -- 一元操作符, 繼承Function<t,t>,傳入參數的類型和返回類型相同。
  • BinaryOperator -- 二元操作符, 傳入的兩個參數的類型和返回類型相同, 繼承BiFunction

Java 8 中的方法引用