一.什麼是函數式接口
最近在開發過程中,發現許多Java8新特性的應用及其廣泛,很多代碼如果不瞭解這些知識是看不懂的,所以打算總結一下。
- 函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
- 函數式接口可以被隱式轉換爲 lambda 表達式
lambda表達式介紹: lambda表達式介紹
代碼示例:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
目前個人理解:函數式接口其實就是一種接口而已,爲什麼它如此特殊是因爲它只有一個抽象方法,方便我們用Lambda表達式等方式來寫代碼
比如上面的接口可以這樣使用:
GreetingService greetService1 = message -> System.out.println("Hello " + message);
二.四大函數式接口
java.util.function 它包含了很多類,用來支持 Java的 函數式編程,其中有許多函數式接口,但是比較基本比較常用的有四種,分別是Function,Consumer,Predicate,Supplier。下面就讓我們一起來學習一下
附常見的泛型類型:
使用大寫字母A,B,C,D......X,Y,Z定義的,就都是泛型,把T換成A也一樣,這裏T只是名字上的意義而已
? 表示不確定的java類型
T (type) 表示具體的一個java類型
K V (key value) 分別代表java鍵值中的Key Value
E (element) 代表Element
1.Function功能型函數式接口
表示接受一個參數併產生結果的函數
@FunctionalInterface
public interface Function<T, R> {
/**
* 接收一個參數,進行操作後將結果返回
*/
R apply(T t);
/**
* 返回一個 先執行before函數對象apply方法,再執行當前函數對象apply方法的 函數對象
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* 返回一個 先執行當前函數對象apply方法, 再執行after函數對象apply方法的 函數對象
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* 返回一個執行了apply()方法之後只會返回輸入參數的函數對象
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
可以看出來Function接口的核心就是apply這個方法。
代碼示例:
public class FunctionDemo {
static int calValue(int value, Function<Integer, Integer> function) {
return function.apply(value);
}
public static void main(String[] args) {
int value = 10;
//lambda表達式
int res = calValue(value, (x) -> {return value + 10;});
System.out.println(res);
}
}
calValue作爲類的靜態方法,傳入一個Function接口作爲參數,返回值是經過函數計算的結果。在main方法中用lambda表達式實現了這個接口,這樣讓函數的擴展性更強了。
2.Predicate斷言型函數式接口
接受一個輸入參數,返回一個布爾值結果。
@FunctionalInterface
public interface Predicate<T> {
/**
* 評估當前參數
*/
boolean test(T t);
/**
* 對應了java的連接符號&&
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* 對應了java的連接符號!
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* 對應了java的連接符號||
*/
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);
}
}
除了主要的抽象方法test外,另外三個方法其實都是用於邏輯判斷的,可以讓我們對斷言進行排列組合,方便編程
int[] numbers= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
List<Integer> list=new ArrayList<>();
for(int i:numbers) {
list.add(i);
}
Predicate<Integer> p1=i->i>5;
Predicate<Integer> p2=i->i<20;
Predicate<Integer> p3=i->i%2==0;
List test=list.stream().filter(p1.and(p2).and(p3)).collect(Collectors.toList());
System.out.println(test.toString());
/** print:[6, 8, 10, 12, 14]*/
需求是輸出偶數,只需要通過stream流式編程然後定義三個Predicate進行過濾即可。
3.Consumer消費型函數式接口
代表了 接受一個輸入參數並且無返回的操作
public static void modifyTheValue(int value, Consumer<Integer> consumer) {
consumer.accept(value);
}
v
public static void main(String[] args) {
// (x) -> System.out.println(x * 2)接受一個輸入參數x
// 直接輸出,並沒有返回結果
// 所以該lambda表達式可以實現Consumer接口
modifyTheValue(3, (x) -> System.out.println(x * 2));
}
輸出結果爲6
4.Supplier供給型函數式接口
無參數,返回一個結果
public static String supplierTest(Supplier<String> supplier) {
return supplier.get();
}
public static void main(String args[]) {
String name = "冷冷";
// () -> name.length() 無參數,返回一個結果(字符串長度)
// 所以該lambda表達式可以實現Supplier接口
System.out.println(supplierTest(() -> name.length() + ""));
}
三.總結
函數式接口爲Java賦予了函數式編程的能力。
“函數式編程"是一種"編程範式”(programming paradigm),也就是如何編寫程序的方法論。它屬於"結構化編程"的一種,主要思想是把運算過程儘量寫成一系列嵌套的函數調用,有許多的好處。