【Java8 新特性】函數式接口 + Lamda表達式推導過程

一、函數式接口簡介

函數式接口是 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註解深入淺出

下一篇:【Java8 新特性】Lambda表達式總結(全棧最強,絕對豪橫)

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