java中functional interface的分類和使用詳解
java 8引入了lambda表達(dá)式,lambda表達(dá)式實(shí)際上表示的就是一個(gè)匿名的function。
在java 8之前,如果需要使用到匿名function需要new一個(gè)類的實(shí)現(xiàn),但是有了lambda表達(dá)式之后,一切都變的非常簡(jiǎn)介。
我們看一個(gè)之前講線程池的時(shí)候的一個(gè)例子:
//ExecutorService using class ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(new Runnable() { @Override public void run() { log.info("new runnable"); } });
executorService.submit
需要接收一個(gè)Runnable類,上面的例子中我們new了一個(gè)Runnable類,并實(shí)現(xiàn)了它的run()方法。
上面的例子如果用lambda表達(dá)式來(lái)重寫(xiě),則如下所示:
//ExecutorService using lambda executorService.submit(()->log.info("new runnable"));
看起是不是很簡(jiǎn)單,使用lambda表達(dá)式就可以省略匿名類的構(gòu)造,并且可讀性更強(qiáng)。
那么是不是所有的匿名類都可以用lambda表達(dá)式來(lái)重構(gòu)呢?也不是。
我們看下Runnable類有什么特點(diǎn):
@FunctionalInterface public interface Runnable
Runnable類上面有一個(gè)@FunctionalInterface
注解。這個(gè)注解就是我們今天要講到的Functional Interface。
Functional Interface
Functional Interface是指帶有 @FunctionalInterface
注解的interface。它的特點(diǎn)是其中只有一個(gè)子類必須要實(shí)現(xiàn)的abstract方法。如果abstract方法前面帶有default關(guān)鍵字,則不做計(jì)算。
其實(shí)這個(gè)也很好理解,因?yàn)镕unctional Interface改寫(xiě)成為lambda表達(dá)式之后,并沒(méi)有指定實(shí)現(xiàn)的哪個(gè)方法,如果有多個(gè)方法需要實(shí)現(xiàn)的話,就會(huì)有問(wèn)題。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FunctionalInterface {}
Functional Interface一般都在java.util.function
包中。
根據(jù)要實(shí)現(xiàn)的方法參數(shù)和返回值的不同,Functional Interface
可以分為很多種,下面我們分別來(lái)介紹。
Function:一個(gè)參數(shù)一個(gè)返回值
Function接口定義了一個(gè)方法,接收一個(gè)參數(shù),返回一個(gè)參數(shù)。
@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t);
一般我們?cè)趯?duì)集合類進(jìn)行處理的時(shí)候,會(huì)用到Function。
Map<String, Integer> nameMap = new HashMap<>(); Integer value = nameMap.computeIfAbsent("name", s -> s.length());
上面的例子中我們調(diào)用了map的computeIfAbsent
方法,傳入一個(gè)Function。
上面的例子還可以改寫(xiě)成更短的:
Integer value1 = nameMap.computeIfAbsent("name", String::length);
Function沒(méi)有指明參數(shù)和返回值的類型,如果需要傳入特定的參數(shù),則可以使用IntFunction, LongFunction, DoubleFunction:
@FunctionalInterface public interface IntFunction<R> { /** * Applies this function to the given argument. * * @param value the function argument * @return the function result */ R apply(int value); }
如果需要返回特定的參數(shù),則可以使用ToIntFunction, ToLongFunction, ToDoubleFunction:
@FunctionalInterface public interface ToDoubleFunction<T> { /** * Applies this function to the given argument. * * @param value the function argument * @return the function result */ double applyAsDouble(T value); }
如果要同時(shí)指定參數(shù)和返回值,則可以使用DoubleToIntFunction, DoubleToLongFunction, IntToDoubleFunction, IntToLongFunction, LongToIntFunction, LongToDoubleFunction:
@FunctionalInterface public interface LongToIntFunction { /** * Applies this function to the given argument. * * @param value the function argument * @return the function result */ int applyAsInt(long value); }
BiFunction:接收兩個(gè)參數(shù),一個(gè)返回值
如果需要接受兩個(gè)參數(shù),一個(gè)返回值的話,可以使用BiFunction:BiFunction, ToDoubleBiFunction, ToIntBiFunction, ToLongBiFunction等。
@FunctionalInterface public interface BiFunction<T, U, R> { /** * Applies this function to the given arguments. * * @param t the first function argument * @param u the second function argument * @return the function result */ R apply(T t, U u);
我們看一個(gè)BiFunction的例子:
//BiFunction Map<String, Integer> salaries = new HashMap<>(); salaries.put("alice", 100); salaries.put("jack", 200); salaries.put("mark", 300); salaries.replaceAll((name, oldValue) -> name.equals("alice") ? oldValue : oldValue + 200);
Supplier:無(wú)參的Function
如果什么參數(shù)都不需要,則可以使用Supplier:
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
Consumer:接收一個(gè)參數(shù),不返回值
Consumer接收一個(gè)參數(shù),但是不返回任何值,我們看下Consumer
的定義:
@FunctionalInterface public interface Consumer<T> { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t);
看一個(gè)Consumer的具體應(yīng)用:
//Consumer nameMap.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
Predicate:接收一個(gè)參數(shù),返回boolean
Predicate接收一個(gè)參數(shù),返回boolean值:
@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t);
如果用在集合類的過(guò)濾上面那是極好的:
//Predicate List<String> names = Arrays.asList("A", "B", "C", "D", "E"); List<String> namesWithA = names.stream() .filter(name -> name.startsWith("A")) .collect(Collectors.toList());
Operator:接收和返回同樣的類型
Operator接收和返回同樣的類型,有很多種Operator:UnaryOperator BinaryOperator ,DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator, LongBinaryOperator等。
@FunctionalInterface public interface IntUnaryOperator { /** * Applies this operator to the given operand. * * @param operand the operand * @return the operator result */ int applyAsInt(int operand);
我們看一個(gè)BinaryOperator的例子:
//Operator List<Integer> values = Arrays.asList(1, 2, 3, 4, 5); int sum = values.stream() .reduce(0, (i1, i2) -> i1 + i2);
Functional Interface是一個(gè)非常有用的新特性,希望大家能夠掌握。
本文的例子:https://github.com/ddean2009/learn-java-streams/tree/master/functional-interface
總結(jié)
到此這篇關(guān)于java中functional interface的分類和使用詳解的文章就介紹到這了,更多相關(guān)java中functional interface的分類和使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot配置文件內(nèi)容加密代碼實(shí)例
這篇文章主要介紹了Springboot配置文件內(nèi)容加密代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11idea中java及java web項(xiàng)目的常見(jiàn)問(wèn)題及解決
在IDEA中處理亂碼問(wèn)題主要涉及四個(gè)方面:文件編碼設(shè)置為UTF-8、編輯器默認(rèn)編碼調(diào)整、Tomcat運(yùn)行配置編碼設(shè)置以及解決cmd中的亂碼,此外,詳細(xì)介紹了在IDEA中創(chuàng)建Web項(xiàng)目的步驟,包括新建Java工程、添加Web框架支持、添加Tomcat依賴庫(kù)2024-09-09springboot項(xiàng)目啟動(dòng)類錯(cuò)誤(找不到或無(wú)法加載主類 com.**Application)
本文主要介紹了spring-boot項(xiàng)目啟動(dòng)類錯(cuò)誤(找不到或無(wú)法加載主類 com.**Application),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05Springboot自定義mvc組件如何實(shí)現(xiàn)
這篇文章主要介紹了Springboot自定義mvc組件如何實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11