一、函數式接口簡介
函數式接口是 Java8 引入的一個新特性,是一種特殊的接口:SAM類型的接口(Single Abstract Method),但本質上還是接口。相比較於其他接口,函數式接口有且只能有一個抽象方法。只要接口中出現多個抽象方法,那麼就不能稱之爲函數式接口,運行的時候就會報錯。爲此 Java8 提供了一個新的註解@FunctionalInterface
,如果接口被這個註解標註,就說明該接口是函數式接口,如果有多於一個的抽象方法,在編譯的時候就會報錯。但是這個註解不是必需的,只要接口符合函數式接口的定義,那麼這個接口就是函數式接口。
簡單來說,一個接口有且只有一個抽象方法,即函數式接口。
二、函數式接口特性
原則上講,函數式接口中有且只能有一個抽象方法。但是在 Java8 之後接口中也是可以定義方法的:默認方法和靜態方法,這兩種方法的定義並不會影響函數式接口的定義,可以隨意使用。即:
1、靜態方法
接口中可以有一個或多個靜態方法,這不會影響到函數式接口的定義。
2、default方法
在 Java8 之後,接口允許定義由 default 修飾的默認方法,並且不強制實現類重寫此方法,這些方法也不會影響到函數式接口的定義。
默認方法不能被直接調用,可以由實現類調用。
注意事項
(1)當一個實現類實現了多個接口,多個接口裏都有相同的默認方法時,實現類必須重寫該默認方法,否則編譯錯誤。
(2)實現類使用super關鍵字指定使用哪個接口的默認方法。
3、函數式接口支持繼承
函數式接口支持繼承,可以繼承多個父接口,但是每個父接口只能有一個抽象方法,且必須是相同的抽象方法。
三、函數式接口的意義
我是這麼理解的,java是面向對象的,但是爲了寫起來方便,需要向一個方法傳遞一個方法,但是實際上並不能傳遞方法,而是傳遞了只有一個抽象方法的接口的實現類的對象,這樣就做到類似傳遞方法了,其實lanmada就是一個對象
四、四種核心的函數式接口
1、功能性接口Function
接收一個功能參數t,並返回一個功能結果R。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
2、斷言性接口:Predicate
主要用到test方法 其中參數t爲輸入參數,如果輸入參數符合斷言則返回true,否則false
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
3、供給性接口:Supplier
不接收任何參數 但有返回值
@FunctionalInterface
public interface Supplier<T> {
T get();
}
4、消費性接口:Consumer
只接收一個參數t,但是沒有返回值。
五、Lambda表達式
Lambda 表達式是 JDK8 的一個新特性,可以取代大部分的匿名內部類,寫出更優雅的 Java 代碼,尤其在集合的遍歷和其他集合操作中,可以極大地優化代碼結構。
雖然使用 Lambda 表達式可以對某些接口進行簡單的實現,但並不是所有的接口都可以使用 Lambda 表達式來實現。Lambda 規定接口中只能有一個需要被實現的方法,不是規定接口中只能有一個方法。
JDK 也提供了大量的內置函數式接口供我們使用,使得 Lambda 表達式的運用更加方便、高效。
簡單明瞭,函數式接口就是爲了Lambda 表達式而生的。
六、Lambda表達式的推導過程
1、匿名內部類 --> Lambda表達式 --> 簡化Lambda表達式
package java8.lamda;
public class LamdaTest {
public static void main(String[] args) {
//匿名內部類
IStudent student = new IStudent() {
@Override
public void study(String technology,int time) {
System.out.println("匿名內部類,"+technology+time);
}
};
student.study("java",8);
//Lambda表達式改造(將類名和方法名去掉)
IStudent student1 = (String technology,int time)->{
System.out.println("Lambda表達式改造(將類名和方法名去掉)"+technology+time);
};
student1.study("java",8);
//一級進化(去掉數據類型)
IStudent student2 = ((technology, time) -> {
System.out.println("一級進化(去掉數據類型)"+technology+time);
});
student2.study("java",8);
//二級進化(簡化括號),一般進行一次進化就可以了,二級進化沒必要
IStudent student3 = ((technology, time) -> System.out.println("二級進化(簡化括號)"+technology+time));
student3.study("java",8);
}
}
@FunctionalInterface
interface IStudent {
void study(String technology,int time);
}
2、控制檯輸出
上一篇:Java註解深入淺出