新聞中心
?技術(shù)的升級(jí)往往不是獨(dú)立的,而是一次系統(tǒng)性的升級(jí),小部分升級(jí)通常是改BUG,JDK8的升級(jí)意義非常重大,各個(gè)升級(jí)環(huán)環(huán)相扣!本篇介紹的函數(shù)式接口和上篇講解的《??Lambda表達(dá)式??》緊密相關(guān)!本篇你只需要搞懂什么是函數(shù)式接口這個(gè)概念就行啦,代碼寫(xiě)不寫(xiě)無(wú)所謂,非常簡(jiǎn)單!

掌握內(nèi)容
- 函數(shù)式接口概念和意義
- 認(rèn)識(shí)JDK內(nèi)置函數(shù)式接口
- 函數(shù)式接口配合Lambda實(shí)現(xiàn)
- 自定義函數(shù)式接口
- @FunctionalInterface注解作用
函數(shù)式接口
函數(shù)式接口就是一個(gè)有且僅有一個(gè)抽象方法,但是可以有多個(gè)非抽象方法的接口,是Lambda表達(dá)式的實(shí)現(xiàn)前提,可以使用@FunctionalInterface注解修飾
函數(shù)式接口意義
Java一直倡導(dǎo)面向?qū)ο?,隨著Python、Scala等語(yǔ)言的興起和新技術(shù)的挑戰(zhàn),Java必須調(diào)整來(lái)支持更加廣泛的技術(shù)要求,所以Java不單單OOP【面向?qū)ο缶幊獭客瑯又С諳OF【面向函數(shù)編程】。
以往需要通過(guò)匿名內(nèi)部類(lèi)實(shí)現(xiàn),現(xiàn)在都可以通過(guò)Lambda實(shí)現(xiàn),其實(shí)Lambda表達(dá)式可以看做是一個(gè)函數(shù)式接口的實(shí)例。
JDK內(nèi)置函數(shù)式接口
注:不需要掌握,不需要掌握!我看網(wǎng)上很多資料都只寫(xiě)了四個(gè)內(nèi)置接口,比較局限,這里對(duì)JDK內(nèi)置接口做一個(gè)全面的說(shuō)明,只需要知道有這么多內(nèi)置接口,并不是只有四個(gè)就可以了。
JDK8新增函數(shù)式接口:
JDK8新推出的函數(shù)式接口在java.util.function包下
作用如下:
|
函數(shù)式接口 |
參數(shù)類(lèi)型 |
返回類(lèi)型 |
用途 |
|
Consumer 消費(fèi)型接口 |
T |
void |
對(duì)類(lèi)型為T(mén)的對(duì)象應(yīng)用操作,包含方法:void accept(T t) |
|
Supplier 供給型接口 |
無(wú) |
T |
返回類(lèi)型為T(mén)的對(duì)象,包含方法:T get() |
|
Function |
T |
R |
對(duì)類(lèi)型為T(mén)的對(duì)象應(yīng)用操作,并返回結(jié)果。結(jié)果是R類(lèi)型的對(duì)象。包含方法:R apply(T t) |
|
Predicate斷定型接口 |
T |
boolean |
確定類(lèi)型為T(mén)的對(duì)象是否滿(mǎn)足某約束,并返回boolean 值。包含方法:boolean test(T t) |
|
BiFunction |
T, U |
R |
對(duì)類(lèi)型為T(mén),U參數(shù)應(yīng)用操作,返回R類(lèi)型的結(jié)果。包含方法為:Rapply(T t,U u) |
|
UnaryOperator(Function子接口) |
T |
T |
對(duì)類(lèi)型為T(mén)的對(duì)象進(jìn)行一元運(yùn)算,并返回T類(lèi)型的結(jié)果。包含方法為:Tapply(T t); |
|
BinaryOperator(BiFunction子接口) |
T,T |
T |
對(duì)類(lèi)型為T(mén)的對(duì)象進(jìn)行二元運(yùn)算,并返回T類(lèi)型的結(jié)果。包含方法為:Tapply(T t1,T t2); |
|
BiConsumer |
T,U |
void |
對(duì)類(lèi)型為T(mén),U參數(shù)應(yīng)用操作。包含方法為:voidaccept(Tt,Uu) |
|
BiPredicate |
T,U |
boolean |
包含方法為:booleantest(Tt,Uu) |
|
ToIntFunction |
T |
int |
計(jì)算int值的函數(shù) |
|
ToLongFunction |
T |
long |
計(jì)算long值的函數(shù) |
|
ToDoubleFunction |
T |
double |
計(jì)算double值的函數(shù) |
|
IntFunction |
int |
R |
參數(shù)為int類(lèi)型的函數(shù) |
|
LongFunction |
long |
R |
參數(shù)為long類(lèi)型的函數(shù) |
|
DoubleFunction |
double |
R |
參數(shù)為double類(lèi)型的函數(shù) |
JDK8之前的函數(shù)式接口:
JDK8之前也存在函數(shù)式接口,在JDK8升級(jí)之后這些接口頭部都加上了@FunctionalInterface修飾,如下:
- java.lang.Runnable【熟悉吧,創(chuàng)建線程】
- java.util.concurrent.Callable【創(chuàng)建線程】
- java.security.PrivilegedAction【執(zhí)行計(jì)算】
- java.util.Comparator【Lambda一篇說(shuō)過(guò)的 比較器】
- java.io.FileFilter【文件過(guò)濾器】
- java.nio.file.PathMatcher【路徑匹配】
- java.lang.reflect.InvocationHandler【動(dòng)態(tài)代理】
- java.beans.PropertyChangeListener【屬性變化監(jiān)聽(tīng)器】
- java.awt.event.ActionListener【事件監(jiān)聽(tīng)器】
- javax.swing.event.ChangeListener【change事件監(jiān)聽(tīng)】
函數(shù)式接口使用
在上篇中我們已經(jīng)使用過(guò)Runnable、Consumer、Supplier、Comparator等接口,這里我們?cè)偈褂肍unction和Predicate接口,其他接口如果用到了可以照葫蘆畫(huà)瓢即可!
Function接口
接口定義如下:
小貼士:接口中有且僅有一個(gè)抽象方法的接口就是一個(gè)函數(shù)式接口,和默認(rèn)實(shí)現(xiàn)以及靜態(tài)方法無(wú)關(guān)。
package java.util.function;
import java.util.Objects;
/**
*
* @param輸入?yún)?shù)類(lèi)型
* @param
@FunctionalInterface
public interface Function{
/**
抽象方法:輸入T類(lèi)型參數(shù),返回R類(lèi)型的值
T和R是泛型哦,小伙伴不要搞混
*/
R apply(T t);
/**
JDK8新特性,接口中可以存在默認(rèn)實(shí)現(xiàn)
*/
defaultFunction compose(Function super V, ? extends T> before){
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
默認(rèn)實(shí)現(xiàn)
*/
defaultFunction andThen(Function super R, ? extends V> after){
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
JDK8接口新特性:可以有靜態(tài)方法
*/
staticFunction identity(){
return t -> t;
}
}
接口特點(diǎn):有一個(gè)輸入?yún)?shù)和一個(gè)輸出參數(shù),也就是一進(jìn)一出,如果你有需求是傳入一個(gè)參數(shù)并返回一個(gè)參數(shù)的需求可以使用該接口實(shí)現(xiàn)。
需求:
實(shí)現(xiàn)一個(gè)字符串轉(zhuǎn)換功能,將輸入的英文字符都轉(zhuǎn)換為大寫(xiě)返回。
分析:
輸入和輸出數(shù)據(jù)都是字符串所有泛型類(lèi)型均為String。
調(diào)用 apply方法進(jìn)行計(jì)算之后接收返回值。
代碼實(shí)現(xiàn):
public class FunctionMain {
public static void main(String[] args) {
// 1、原始匿名內(nèi)部類(lèi)寫(xiě)法
Function function1 = new Function() {
@Override
public String apply(String inputStr) {
// 轉(zhuǎn)換為大寫(xiě)
return inputStr.toUpperCase();
}
};
String result = function1.apply("Just give me a chance to start!");
System.out.println(result);
// 2、Lambda表達(dá)式寫(xiě)法
Function function2 = inputStr -> inputStr.toUpperCase();
String lambdaResult = function2.apply("Lambda really smells good!");
System.out.println(lambdaResult);
}
}
Predicate接口
接口定義:
該接口也存在默認(rèn)實(shí)現(xiàn)和靜態(tài)方法,但是只有一個(gè)抽象方法,所以也是一個(gè)函數(shù)式接口。
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate{
/**
根據(jù)參數(shù)輸入判斷是否正確,返回true或者false
*/
boolean test(T t);
default Predicateand(Predicate super T> other){
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicatenegate(){
return (t) -> !test(t);
}
default Predicateor(Predicate super T> other){
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
staticPredicate isEqual(Object targetRef){
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
接口特點(diǎn):該接口根據(jù)傳入數(shù)據(jù)通過(guò)計(jì)算之后返回true或者false,如果你想要做單個(gè)參數(shù)的判斷可以使用該接口。
小貼士:Java中有兩個(gè)Predicate類(lèi),不要導(dǎo)錯(cuò)包,認(rèn)準(zhǔn)java.util.function包,當(dāng)然自定義的類(lèi)也不要起這個(gè)名字,【有許多初學(xué)者喜歡起同名的類(lèi)】。
需求:判斷輸入的數(shù)據(jù)是否大于0。
分析:
- 泛型定義為Integer類(lèi)型。
- 通過(guò)判斷返回結(jié)果即可。
代碼實(shí)現(xiàn):
public class PredicateMain {
public static void main(String[] args){
// 1、原始實(shí)現(xiàn)方式
Predicate predicate1 = new Predicate() {
@Override
public boolean test(Integer num){
return num > 0;
}
};
// 調(diào)用test方法
boolean result = predicate1.test(1024);
System.out.println(result);
// 2、Lambda表達(dá)式實(shí)現(xiàn)
Predicate predicate2 = num -> num > 0;
// 調(diào)用test方法
boolean lambdaResult = predicate2.test(-1024);
System.out.println(lambdaResult);
}
}
小貼士:這些默認(rèn)方法的接口,使用時(shí)不要調(diào)用錯(cuò)方法就行!
自定義函數(shù)式接口
分析:
函數(shù)式接口就是有且僅有一個(gè)抽象方法,默認(rèn)實(shí)現(xiàn)和靜態(tài)方法不影響它是一個(gè)函數(shù)式接口【JDK8支持接口有默認(rèn)方法和靜態(tài)方法】。
接口,定義抽象即可,所以我這里都使用泛型,可以根據(jù)自己的需求定義,如果需求要限制類(lèi)型也可以直接定義成具體的類(lèi)型。
接口定義:
package com.stt.function.myfunction;
/**
* 自定義函數(shù)式接口:
* 定義:
* 1、接口中只有一個(gè)抽象方法
* 2、可以使用@FunctionInterface注釋修飾,也可以不使用
* 如果使用該注解報(bào)錯(cuò),說(shuō)明該接口不是一個(gè)函數(shù)式接口
*/
@FunctionalInterface
public interface SttFunction{
/**
* 接收兩個(gè)參數(shù),并返回一個(gè)參數(shù)
* 注意:接口嘛,定義個(gè)大概就行了,具體什么參數(shù),怎么返回就不需要說(shuō)明了,具體實(shí)現(xiàn)的時(shí)候再說(shuō)唄
*/
V calc(T t,R r);
}
接口使用:
package com.stt.function.myfunction;
public class SttFunctionMain {
public static void main(String[] args) {
// 1、原始方式,匿名內(nèi)部類(lèi)實(shí)現(xiàn)
SttFunctionsttFunction1 = new SttFunction () {
@Override
public Integer calc(Integer num1, Integer num2) {
return num1 * num2;
}
};
Integer result = sttFunction1.calc(2, 2);
System.out.println(result);
// 2、Lambda表達(dá)式調(diào)用
SttFunctionsttFunction = (num1,num2) -> num1 + num2;;
Integer lambdaResult = sttFunction.calc(1023, 1);
System.out.println(lambdaResult);
}
}
Lambda表達(dá)式就是香。
包含默認(rèn)實(shí)現(xiàn)的函數(shù)式接口:
包含默認(rèn)方法和靜態(tài)方法并不影響它是一個(gè)函數(shù)式接口。
package com.stt.function.myfunction;
/**
* 自定義函數(shù)式接口:
* 定義:
* 1、接口中只有一個(gè)抽象方法
* 2、可以使用@FunctionInterface注釋修飾,也可以不使用
* 如果使用該注解報(bào)錯(cuò),說(shuō)明該接口不是一個(gè)函數(shù)式接口
*/
@FunctionalInterface
public interface SttFunction{
/**
* 接收兩個(gè)參數(shù),并返回一個(gè)參數(shù)
* 注意:接口嘛,定義個(gè)大概就行了,具體什么參數(shù),怎么返回就不需要說(shuō)明了,具體實(shí)現(xiàn)的時(shí)候再說(shuō)唄
*/
V calc(T t,R r);
default void defaultMethod(){
System.out.println("也不知道實(shí)現(xiàn)點(diǎn)什么,反正JDK8之后可以有默認(rèn)實(shí)現(xiàn)!");
}
static void staticMethod(){
System.out.println("同樣不知道寫(xiě)點(diǎn)什么,反正JDK8之后可以有靜態(tài)方法!");
}
}
有多個(gè)抽象方法:
有兩個(gè)以上抽象方法就不再是一個(gè)函數(shù)式接口,所以@FunctionalInterface注解報(bào)錯(cuò),該注解可以用來(lái)檢驗(yàn)接口是否為一個(gè)函數(shù)式接口。
@FunctionalInterface注解
Java 8中專(zhuān)門(mén)為函數(shù)式接口引入了一個(gè)新的注解:@FunctionalInterface 。該注解放在接口上,表示此接口是一個(gè)函數(shù)式接口。并且提示編譯器去檢查接口是否僅包含一個(gè)抽象方法,即,是否符合函數(shù)式編程的定義。
小貼士:如果自定義一個(gè)符合規(guī)范的函數(shù)式接口,也可以不加@FunctionalInterface注解,此注解只是起到一個(gè)提示編譯器進(jìn)行規(guī)范檢查的作用
總結(jié)
- 技術(shù)升級(jí)都是系統(tǒng)性的,僅升級(jí)修改某一部分通常是修復(fù)BUG。
- 函數(shù)式接口是Lambda的前提,JDK8之前通過(guò)匿名內(nèi)部類(lèi)實(shí)現(xiàn),Lambda讓編碼變的簡(jiǎn)潔。
- 函數(shù)式接口中有且僅有一個(gè)抽象方法。
- 函數(shù)式接口可以使用@FunctionalInterface檢驗(yàn),也可以不使用該注解。
- JDK內(nèi)置了許多函數(shù)式接口,可以按需使用,我們也可以自定義函數(shù)式接口。
- 在閱讀部分框架源碼時(shí)一定要認(rèn)識(shí)Lambda表達(dá)式和函數(shù)式接口哦?。
文章出自:??添甄??,如有轉(zhuǎn)載本文請(qǐng)聯(lián)系【添甄】今日頭條號(hào)。
網(wǎng)站題目:結(jié)合Java所有特性,系統(tǒng)全面講解函數(shù)式接口及應(yīng)用
轉(zhuǎn)載來(lái)源:http://www.5511xx.com/article/djjgope.html


咨詢(xún)
建站咨詢(xún)
