什麼是函數式接口
函數式接口是Java8引用的一個新特性,是一種特殊的接口:SAM類型的接口(Single Abstract Method)。但是它還是一個接口,隻是有些特殊罷了。 函數式接口的出現主要是為了配合Java8的另一個新特性Lamdba表達式來使用。
- 接口中隻有一個抽象方法
- 接口中面可以加一個注解@FunctionalInterface來檢查接口中的方法是不是隻有一個抽象方法
- 在接口裡面可以加入 預設方法 和 靜态方法
- 函數式接口也可以繼承,但是繼承的時候,抽象方法必須一樣
- 函數式接口重寫父類的的方法,并不會計入到自己的抽象方法中
自定義函數式接口
//加入這個注解是為了檢測接口中是否符合函數式接口的要求
@FunctionalInterface
public interface MyFunctionInterction {
//唯一的抽象方法
void absoluMethod();
//重寫Object的方法
@Override
String toString();
//預設方法
default void defaultMethod() {
System.out.println("預設方法");
}
//靜态方法
static void stativMethod() {
System.out.println("靜态方法");
}
}
函數式接口的簡單使用
裡面的預設方法可以直接使用
public class TestFunctionIntection {
public static void main(String[] args) {
TestFunctionIntection testFunctionIntection =
new TestFunctionIntection();
testFunctionIntection.test(
//Lamdba表達式的簡單使用
() -> System.out.println("函數式接口裡面的抽象方法"));
}
/**
* 自己定義的一個方法,并使用自定義的一個消費類型的函數式接口
* @param myFunctionInterction
*/
public void test(MyFunctionInterction
myFunctionInterction) {
//函數式接口裡面的抽象方法
myFunctionInterction.absoluMethod();
//預設方法
myFunctionInterction.defaultMethod();
//靜态方法
MyFunctionInterction.stativMethod();
}
}
java8裡面自定義的四個核心的函數式接口
上面我自定義的一個接口,就是一個消費類型的函數式接口。其實這類接口在java.util.function裡面有定義的,就是void Consumer< T >,消費類型接口,上面代碼中的test方法裡面的接口其實可以換成Consumer< T >接口,也可以用,下面主要就是介紹這四個函數式接口的簡單使用。
下面是這四個核心接口的簡單使用
public class FunctionTest {
//Consumer<T> 消費型接口
@Test
public void test1() {
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("消費型接口,沒有傳回值!");
}
//輸出:消費型接口,沒有傳回值!
//供給型接口
@Test
public void test2() {
Supplier<String> supplier = () -> "主要的作用就是建立對象!";
String s = supplier.get();
System.out.println(s);
}
//輸出:主要的作用就是建立對象!
//函數型接口
//Function<T,R> T 接收的參數,R 傳回值類型
@Test
public void test3() {
Function<Integer, String> function = (x) -> x + ":為String類型";
String apply = function.apply(7);
System.out.println(apply);
}
//輸出:7:為String類型
//斷言型接口
@Test
public void test4() {
Predicate<Integer> predicate = (x) -> x > 10;
boolean test = predicate.test(11);
System.out.println(test);
}
//輸出:true
}
Consumer 的應用
//Consumer<T> 消費型接口
@Test
public void test1() {
//定義一個消費型接口,隻輸出輸入的内容
Consumer<String> consumer = (x) -> System.out.println(x);
//在輸入的内容後面加上·--加上了預設方法·
Consumer<String> consumer2 = (x) -> System.out.println(x + "--加上了預設方法");
//執行順序 先執行 accept 後面執行 addThen(然後)
consumer.andThen(consumer2).accept("消費型接口,沒有傳回值!");
}
//輸出:消費型接口,沒有傳回值 (accept輸出的值)
//輸出:消費型接口,沒有傳回值 !--加上了預設方法 (addThen輸出的值)
Consumer 的預設方法的源碼:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
其傳回值這一句是重點,先是傳入一個Consumer接口,然後傳回一個Consumer接口,說明可以用表達式鍊,然後用這個特性可以把資料進一次進行加工。
(T t) -> { accept(t); after.accept(t); };這一句,傳回的順序首先是調用抽象方法,然後再調用預設方法,說明這個預設方法隻可以對資料進行再加工,不能再抽象方法前面。
Supplier 的應用
//供給型接口,這個方法若以用在工廠方法中
@Test
public void test2() {
//跟據一個字元串建立對象
Supplier<String> supplier = () -> "主要的作用就是建立對象!";
//擷取一個對象
String s = supplier.get();
//擷取兩個以象
String s1 = supplier.get();
//兩個對象内容一樣
System.out.println(s.equals(s1));
System.out.println(s);
//用方法引用的方式建立一個對象
Supplier<SupplierTest> testSupplier = SupplierTest::new;
//用new的方式建立一個對象
Supplier<SupplierTest> supplierTestSupplier = () -> new SupplierTest("張三");
//可以通過supplierTestSupplier 來擷取一個對象,并且可以調用裡面的方法
String name = supplierTestSupplier.get().getName();
System.out.println(name);
}
//輸出:true
//輸出:主要的作用就是建立對象!
//輸出:張三
Supplier< T >接口類型就有一個方法簽名。T get()方法,沒有預設方法。
Function< T,R > 的應用
//預設主法addThen
//函數型接口
//Function<T,R> T 接收的參數,R 傳回值類型
@Test
public void test3() {
Function<String, String> f1 = (x) -> x +"+ ";
Function<String, String> f2 = (x) -> x + "- ";
//addThen(然後的意思)執行順序先執行f1,并且把執行後的結果作為f2的輸入參數
String apply = f1.andThen(f2).apply("1");
System.out.println(apply);
}
//輸出:1+ -
addThen的源碼:
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
源碼中最重要的一句
(V v) -> apply(before.apply(v)); 規定了執行順序
//預設主法compose
//函數型接口
//Function<T,R> T 接收的參數,R 傳回值類型
@Test
public void test3() {
Function<String, String> f1 = (x) -> x +"+ ";
Function<String, String> f2 = (x) -> x + "- ";
//addThen(然後的意思)執行順序先執行f2,并且把執行後的結果作為f1的輸入參數
String apply = f1.compose(f2).apply("1");
System.out.println(apply);
}
//輸出:1- +
三個預設方法,但是最後一個用的不多,這裡也就不再介紹了。
Predicate< T > 的應用
//默主方法negate 非
//斷言型接口
@Test
public void test4() {
Predicate<Integer> predicate = (x) -> x > 10;
boolean test = predicate.negate().test(11);
System.out.println(test);
}
//輸出:false
//斷言型接口
//預設方法 or 和 and
@Test
public void test4() {
Predicate<Integer> p1 = (x) -> x > 10;
Predicate<Integer> p2 = (x) -> x < 5;
//預設方法 or 或
boolean test = p1.or(p2).test(3);
//預設方法 and 且
boolean test2 = p1.and(p2).test(3);
System.out.println(test);
System.out.println(test2);
}
//輸出:true
//輸出:false
函數式接口的使用
函數式接口的的使用,大部分都是在流操作裡面進行,現在可以不太了解,但是可以在學習完流操作以後,再過來看,并且跟着寫一遍。代碼光看是沒有用的。如果不寫是不知道意思的。
參考的部落格:淺淺的函數式接口
我的公衆号
細節決定成敗!
個人愚見,如有不對,懇請斧正!