1. 程式人生 > >java8新特性之函式式介面

java8新特性之函式式介面

雖然剛釋出了java11版本,但是對於java8中新的特性我們仍需要掌握,畢竟大部分開發都是用的jdk8,以及java11中仍然保留著這些特性,接下來我就網上查詢資料做了一下總結,如果哪裡說的不對頭,還請各位大佬指出來,我會及時更正。

1.函式式介面定義:

那麼函式介面到底是什麼呢?是個介面,只包含一個抽象方法,那麼它就是函式式介面,我們可以在任意函式式介面上使用 @FunctionalInterface 檢查它是否是一個函式式介面,也可不新增該註解,如:

public interface Test {

    default void defaultMethod(){
        System.out.println("Test defalut 方法");
    }

    int sub(int a,int b);

    static void staticMethod() {
        System.out.println("Test static 方法");
    }
}

2.特點

函式式接口裡是可以包含預設方法、靜態方法,他們不是抽象方法;也可以包含Java.lang.Object裡的public方法,因為任何一個類都繼承Object類,包含了來自java.lang.Object裡對這些抽象方法的實現,也不屬於抽象方法;函式式接口裡允許子介面繼承多個父介面,但每個父介面中都只能存在一個抽象方法,且必須的相同的抽象方法,一般和Lamdba表示式一起用,總結下分為兩點:

函式式介面是僅制定一個抽象方法的介面,

可以包含一個或多個靜態或預設方法.

3.該類介面中的static方法不能被繼承,也不能被實現類呼叫,只能被自身呼叫

定義一個函式式介面:

public interface DefalutTest {
    static int a =5;
    default void defaultMethod(){
        System.out.println("DefalutTest defalut 方法");
    }

    int sub(int a,int b);

    static void staticMethod() {
        System.out.println("DefalutTest static 方法");
    }
}

實現該介面:

public class DefaultTestImpl implements DefalutTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

}

測試:

public static void main(String[] args) {
        DefaultTestImpl dt = new DefaultTestImpl();
        dt.defaultMethod(); //介面中的預設方法可以通過實現類物件呼叫
        DefalutTest.staticMethod();//介面中靜態不能通過實現類物件呼叫,只能通過介面本身呼叫
    }

發現實現類物件能夠呼叫介面的預設方法,不能呼叫靜態方法。但是靜態方法可通過介面本身呼叫。

繼承也是這種情況,就不細說了。所以得出結論:

接口裡的靜態方法,即static修飾的有方法體的方法不會被繼承或者實現,但是靜態變數會被繼承 

4.該類介面中的預設方法

①default方法可以被子介面繼承亦可被其實現類所呼叫

準備一個子介面繼承DefalutTest介面

public interface SubTest extends DefalutTest{

}

準備一個子介面的實現類

public class SubTestImp implements SubTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

}

現在我們建立一個子介面實現類物件,並呼叫物件中的default方法:

public class Main {

    public static void main(String[] args) {
        SubTestImp st = new SubTestImp();
        stl.defaultMethod();

    }
}

執行結果: DefalutTest defalut 方法

②default方法被繼承時,可以被子介面覆寫

現在我們在子介面中重寫default方法,在進行呼叫:

public interface SubTest extends DefalutTest{

    default void defaultMethod(){
        System.out.println("SubTest defalut 方法");
    }
}

執行結果:SubTest defalut 方法

③如果一個類實現了多個介面,且這些介面中無繼承關係,這些介面中若有相同的(同名,同參數)的default方法,則介面實現類會報錯,介面實現類必須通過特殊語法指定該實現類要實現那個介面的default方法 

我們去除介面間的繼承關係,並使得SubTestImp同時實現父介面和子介面,我們知道此時父介面和子介面中存在同名同參數的default方法,這會怎麼樣?  結果實現類報錯,實現類要求必須指定他要實現那個介面中的default方法:  

解決方法:使用特殊語法:<介面>.super.<方法名>([引數]) 

public class SubTestImp implements SubTest,DefalutTest{

    @Override
    public int sub(int a, int b) {
        // TODO Auto-generated method stub
        return a-b;
    }

    @Override
    public void defaultMethod() {
        // TODO Auto-generated method stub
        DefalutTest.super.defaultMethod();
    }

}

5.Java8內建函式式介面

四大核心函式式介面

函式式介面 方法 引數型別 返回型別 作用
Consumer<T> 消費型介面 void accept(T t) T void 對T型別的引數進行操作
Supplier<T> 供給型介面 T get() T 操作資料,返回T型別的結果
Function<T, R> 函式型介面 R apply(T t) T R 對T型別引數進行操作,並返回R型別的結果
Predicate<T> 斷定型介面 boolean test(T t) T boolean 確定T型別引數是否滿足某約束,並返回boolean值
//Consumer<T> 消費型介面
  @Test
  public void test1(){
    Consumer<String> c = (x) -> System.out.println("hello:"+x+"!");
    c.accept("Java");
  }
  // Supplier<T> 供給型介面
  @Test
  public void test2(){
    Supplier<String> s = () -> "hello,beautiful girl";
    String str = s.get();
    System.out.println(str);
  }
  //Function<T,R> 函式性介面
  @Test
  public void test3(){
    Function<String, Integer> f= (x) -> x.length();
    Integer len = f.apply("hello");
    System.out.println(len);
  }
  //Predicate<T> 斷言型介面
  @Test
  public void test4(){
    Predicate<String> p = (x) -> x.length()>5;
    boolean b = p.test("hello Java");
    System.out.println(b);
  }