JDK8新特性之函數式接口

什麼是函數式接口

先來看看傳統的建立線程是怎麼寫的java

Thread t1 = new Thread(new Runnable() {
	@Override
	public void run() {
		System.out.println("t1");
	}
});
t1.start();
複製代碼

再來看看使用了函數式接口是怎麼寫的bash

Thread t2 = new Thread(() -> System.out.println("t2"));
t2.start();
複製代碼

Runnable接口直接能夠使用Lambda表達式來編寫,這是由於Runnable接口是一個函數式接口,來看看Runnable的源碼。微信

@FunctionalInterface
public interface Runnable {

    public abstract void run();
    
}
複製代碼

發現該接口加上了函數式接口的定義註解:@FunctionalInterface,代表該接口是一個函數式接口。多線程

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {
    
}
複製代碼

在JDK8中,除了Runnbale接口,還有像Comparator、Callable等接口都加上了該註解定義爲函數式接口。app

內置函數式接口

JDK8提供了幾個內置的函數式接口,用在了許多API的地方,均可以拿來用,能夠知足大部分應用。ide

//Consumer<T> - T做爲輸入,執行某種動做但沒有返回值
Consumer<String> con = (x) -> {
	System.out.println(x);
};
con.accept("hello world");

//Supplier<T> - 沒有任何輸入,返回T
Supplier<String> supp = () -> {
	return "Supplier";
};
System.out.println(supp.get());

//Predicate<T> -T做爲輸入,返回的boolean值做爲輸出
Predicate<String> pre = (x) -> {
	System.out.print(x);
	return x.startsWith("op");
};
System.out.println(": " + pre.test("op, hello World"));

// Function<T, R> -T做爲輸入,返回的R做爲輸出
Function<String, String> function = (x) -> {
	System.out.print(x + ": ");
	return "Function";
};
System.out.println(function.apply("hello world"));

//BinaryOperator<T> -兩個T做爲輸入,返回一個T做爲輸出,對於「reduce」操做頗有用
BinaryOperator<String> bina = (x, y) -> {
	System.out.print(x + " " + y);
	return "BinaryOperator";
};
System.out.println(" " + bina.apply("hello ", "world"));
複製代碼

自定義函數式接口

一、自定義一個函數式接口

@FunctionalInterface
public interface CalcInterface<N, V> {	
	V operation(N n1, N n2);
}
複製代碼

這裏只有一個抽象方法,@FunctionalInterface註解能夠不用寫,至於爲何能夠往下看。函數

二、新建一個引用函數式接口的類

public static class NumberOperation<N extends Number, V extends Number> {

	private N n1;
	private N n2;

	public NumberOperation(N n1, N n2) {
		this.n1 = n1;
		this.n2 = n2;
	}

	public V calc(CalcInterface<N, V> ci) {
		V v = ci.operation(n1, n2);
		return v;
	}

}
複製代碼

三、測試函數式接口

private static void testOperationFnInterface() {
        NumberOperation<Integer, Integer> np = new NumberOperation(13, 10);
    
	CalcInterface<Integer, Integer> addOper1 = (n1, n2) -> {
		return n1 + n2;
	};
	CalcInterface<Integer, Integer> multiOper1 = (n1, n2) -> {
		return n1 * n2;
	};
	System.out.println(np.calc1(addOper1));
	System.out.println(np.calc1(multiOper1));
	
	// 上面的能夠簡寫爲
	System.out.println(np.calc1((n1, n2) -> n1 + n2));
	System.out.println(np.calc1((n1, n2) -> n1 * n2));
}
複製代碼

最後輸出:測試

23
130
23
130
複製代碼

函數式接口規範

一、@FunctionalInterface標識爲一個函數式接口只能用在只有一個抽象方法的接口上。ui

二、接口中的靜態方法、默認方法、覆蓋了Object類的方法都不算抽象方法。this

三、@FunctionalInterface註解不是必須的,若是該接口只有一個抽象方法能夠不寫,它默認就符合函數式接口,但建議都寫上該註解,編譯器會檢查該接口是否符合函數式接口的規範。

舉例說明

正確的函數式接口。

@FunctionalInterface
public interface CalcInterface<N, V> {	
	V operation(N n1, N n2);
}
複製代碼

加了幾個符合函數式的方法也沒事,編譯器也不會報錯。

@FunctionalInterface
public interface CalcInterface<N, V> {		

	V operation(N n1, N n2);
   
	public boolean equals(Object object);

	public default void defaultMethod() {

	}

	public static void staticMethod() {

	}
}
複製代碼

這個沒用@FunctionalInterface函數式接口,有兩個抽象方法,不能用於Lambda表達式。

public interface CalcInterface<N, V> {	
	V operation(N n1, N n2);
	V operation2(N n1, N n2);
}
複製代碼

這個有兩個抽象方法的用@FunctionalInterface註解的函數式接口編譯會報錯。

@FunctionalInterface
public interface CalcInterface<N, V> {	
	V operation(N n1, N n2);
	V operation2(N n1, N n2);
}
複製代碼

這個沒有一個抽象方法,編譯報錯。

public interface CalcInterface<N, V> {	
}
複製代碼

掃碼關注Java技術棧微信公衆號,在後臺回覆:java,獲取棧長整理的一份最新 Java 技術教程,內容包括 Java 基礎、多線程、JVM、新特性等更多實戰乾貨。

相關文章
相關標籤/搜索