Java中使用回調(diào)函數(shù)的方法實(shí)例
背景
在Java中一個回調(diào)的操作是一個在一些操作完成之后被傳遞到另一個函數(shù)中并且被執(zhí)行的函數(shù)。一個回調(diào)函數(shù)既可以被同步或者異步執(zhí)行。在一個同步回調(diào)函數(shù)的案例中,一個函數(shù)緊著著另一個函數(shù)完成后被執(zhí)行。在一個異步回調(diào)函數(shù)的案例中,一個函數(shù)不需要在其他函數(shù)執(zhí)行的過程中按照特定順序時間內(nèi)被執(zhí)行。
從在經(jīng)典的監(jiān)視者設(shè)計(jì)模式中使用的監(jiān)聽案例開始,這篇文章向你介紹了Java中的回調(diào)函數(shù)。你將會看到大量的同步和異步的回調(diào)實(shí)現(xiàn),包含使用 CompletableFuture類的函數(shù)式回調(diào)。
Java中的同步回調(diào)
一個同步回調(diào)函數(shù)總是會在一些操作執(zhí)行后立刻被執(zhí)行。這意味著它將會在動作被執(zhí)行后執(zhí)行。
正如我提到的,在一個監(jiān)視者設(shè)計(jì)模式中使用的一個回調(diào)函數(shù)的案例。在頁面UI的按鈕中,需要一個按鈕被點(diǎn)擊后去實(shí)例化一個操作,我們可以傳遞回調(diào)函數(shù)作為這個按鈕動作的監(jiān)聽器。這個監(jiān)聽函數(shù)會一直等待按鈕被點(diǎn)擊,直到按鈕被觸發(fā)后執(zhí)行。
現(xiàn)在讓我們看代碼中一個新的回調(diào)概念的案例
匿名內(nèi)部類中的回調(diào)
任何時間我們在Java中,傳遞一個實(shí)現(xiàn)了接口的方法到另一個方法中,我們就是使用了回調(diào)函數(shù)的概念。在下面的代碼中,我們傳遞了一個Consumer函數(shù)接口和一個匿名內(nèi)部類去實(shí)現(xiàn)accept()方法。
一旦 accept() 方法被實(shí)現(xiàn),我們將會在performAction方法里面執(zhí)行它;然后我們會在Consumer接口里面執(zhí)行accept() 方法。
import java.util.function.Consumer; public class AnonymousClassCallback { ? public static void main(String[] args) { ? ? performAction(new Consumer<String>() { ? ? ? @Override ? ? ? public void accept(String s) { ? ? ? ? System.out.println(s); ? ? ? } ? ? }); ? } ? public static void performAction(Consumer<String> consumer) { ? ? System.out.println("Action is being performed..."); ? ? consumer.accept("Callback is executed"); ? } }
該代碼的輸出語句是:
Action is being performed…
Callback is executed…
在以上代碼中,我們將Consumer接口傳遞到performAction() 方法中,然后performAction()方法執(zhí)行后,調(diào)用accept()方法。
你可能注意到,使用一個匿名內(nèi)部類是相當(dāng)?shù)膯?。使用lambda表達(dá)式替代匿名內(nèi)部類將會更簡單。讓我們看看當(dāng)我們在回調(diào)函數(shù)中使用lambda表達(dá)式會發(fā)生什么。
lambda的回調(diào)
在Java中,我們可以傳遞使用了lambda表達(dá)式實(shí)現(xiàn)的函數(shù)式接口到一個方法中,然后在一個操作結(jié)束后被執(zhí)行。在代碼中看起開是那樣。
public class LambdaCallback { ? public static void main(String[] args) { ? ? performAction(() -> System.out.println("Callback function executed...")); ? } ? public static void performAction(Runnable runnable) { ? ? System.out.println("Action is being performed..."); ? ? runnable.run(); ? } }
輸出結(jié)果表明,一旦這個操作執(zhí)行后,回調(diào)即被調(diào)用。
在這個例子中,你可能注意到我們在performAction方法中傳遞了可運(yùn)行的函數(shù)式接口。因此,我們可以重寫run()方法并在performAction方法結(jié)束后執(zhí)行run()方法。
異步回調(diào)函數(shù)
我們經(jīng)常想去使用一個異步回調(diào)方法,這意味著一個方法將會在操作執(zhí)行時被其他進(jìn)程異步地調(diào)用。當(dāng)一個回調(diào)方法不需要被其他進(jìn)程立刻調(diào)用的時候,它可能對性能有所幫助。
簡單線程回調(diào)
讓我們以最簡單的異步回調(diào)操作方式開始。在下面的代碼中,首先我們從一個可執(zhí)行的函數(shù)式接口中實(shí)現(xiàn)了run()方法。然后我們在一個創(chuàng)建線程中使用了它。最終,我們將會啟動這個線程去異步地執(zhí)行這個已實(shí)現(xiàn)的可執(zhí)行函數(shù)式接口:
public class AsynchronousCallback { ? public static void main(String[] args) { ? ? Runnable runnable = () -> System.out.println("Callback executed..."); ? ? AsynchronousCallback asynchronousCallback = new AsynchronousCallback(); ? ? asynchronousCallback.performAsynchronousAction(runnable); ? } ? public void performAsynchronousAction(Runnable runnable) { ? ? new Thread(() -> { ? ? ? System.out.println("Processing Asynchronous Task..."); ? ? ? runnable.run(); ? ? }).start(); ? } }
這個案例的輸出結(jié)果是:
Processing Asynchronous Task…
Callback executed…
從上面的代碼中,我們創(chuàng)建了一個實(shí)現(xiàn)run()方法的Runnable,然后我們調(diào)用performAsynchronousAction()方法,傳遞了Runnable,在新建的線程中run()方法調(diào)用了它。
在performAsynchronousAction() 方法內(nèi),我們向它傳遞了一個runnable參數(shù),在方法內(nèi)部用lambda實(shí)現(xiàn)了一個線程的run方法調(diào)用了它.。先打印 “Processing Asynchronous Task…” 最終方法內(nèi)部調(diào)用了以參數(shù)傳進(jìn)來的runnable方法,打印 “Callback executed…”
平行執(zhí)行的異步回調(diào)
比起在異步調(diào)用中回調(diào)函數(shù),我們也可以從其他函數(shù)中平行地調(diào)用一個回調(diào)函數(shù)。這意味著我們可以開啟兩個線程,平行地調(diào)用這兩個函數(shù)。
以下代碼和之前的有點(diǎn)像,但是要注意到除了直接調(diào)用回調(diào)函數(shù)外,我們可以開啟一個新的線程調(diào)用回調(diào)函數(shù):
// Omitted code from above… public void performAsynchronousAction(Runnable runnable) { ? ? new Thread(() -> { ? ? ? System.out.println("Processing Asynchronous Task..."); ? ? ? new Thread(runnable).start(); ? ? }).start(); ? }
輸出結(jié)果是:
Processing Asynchronous Task…
Callback executed…
當(dāng)我們不需要回調(diào)函數(shù)在performAsynchronousAction() 方法調(diào)用之后被立刻執(zhí)行,異步平行調(diào)用回調(diào)函數(shù)是非常有用的。
一個真實(shí)世界的案例,當(dāng)我們在線上購買一個產(chǎn)品,我們不需要等待付款被確認(rèn)后才執(zhí)行檢查庫存等所有的這些重度操作。在這個案例中,回調(diào)在后臺執(zhí)行的同時我們可以做其他事情。
CompletableFuture中的回調(diào)
使用異步回調(diào)函數(shù)的另一種方法是使用CompletableFuture API。Java8中引入的這個強(qiáng)大的API有助于執(zhí)行和組合異步方法調(diào)用。它完成了我們在上一個示例中所做的一切,例如創(chuàng)建一個新的線程,然后啟動和管理它。
在下面的代碼示例中,我們將創(chuàng)建一個新的CompletableFuture,然后調(diào)用傳遞String的supplyAsync方法。
接下來,我們將創(chuàng)建另一個CompletableFuture,它將應(yīng)用回調(diào)函數(shù)來執(zhí)行我們配置的第一個函數(shù):
import java.util.concurrent.CompletableFuture; public class CompletableFutureCallback { ? public static void main(String[] args) throws Exception { ? ? CompletableFuture<String> completableFuture ? ? ? ? = CompletableFuture.supplyAsync(() -> "Supply Async..."); ? ? CompletableFuture<String> execution = completableFuture ? ? ? ? .thenApply(s -> s + " Callback executed..."); ? ? System.out.println(execution.get()); ? } }
它的輸出結(jié)果如下:
Supply Async… Callback executed…
結(jié)論
回調(diào)在軟件開發(fā)中到處使用,廣泛地使用在工具、設(shè)計(jì)模式和應(yīng)用程序中。有時候我們使用它們的時候卻沒有注意到。
在java代碼中,我們通過大量常見的回調(diào)實(shí)現(xiàn)幫助我們解釋它們廣泛的用處。這里有一些回調(diào)的特征需要我們記?。?/p>
- 回調(diào)函數(shù)應(yīng)該在執(zhí)行另一個操作時執(zhí)行,或者與該操作并行執(zhí)行。
- 回調(diào)函數(shù)可以被同步執(zhí)行,意味著它可以在其他操作執(zhí)行后沒有延遲地被立刻執(zhí)行。
- 回調(diào)函數(shù)可以是異步的,這意味著它可以在后臺執(zhí)行,并且可能需要一些時間才能執(zhí)行
- Observable設(shè)計(jì)模式使用回調(diào)來通知感興趣的實(shí)體何時發(fā)生了操作。
到此這篇關(guān)于Java中使用回調(diào)函數(shù)的方法實(shí)例的文章就介紹到這了,更多相關(guān)Java 回調(diào)函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Framework遠(yuǎn)程代碼執(zhí)行漏洞分析(最新漏洞)
Spring Framework 是一個開源應(yīng)用框架,旨在降低應(yīng)用程序開發(fā)的復(fù)雜度,它具有分層體系結(jié)構(gòu),允許用戶選擇組件,同時還為 J2EE 應(yīng)用程序開發(fā)提供了一個有凝聚力的框架,對Spring遠(yuǎn)程代碼執(zhí)行漏洞相關(guān)知識感興趣的朋友一起看看吧2022-04-04Spring boot整合shiro+jwt實(shí)現(xiàn)前后端分離
這篇文章主要為大家詳細(xì)介紹了Spring boot整合shiro+jwt實(shí)現(xiàn)前后端分離,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12idea中增強(qiáng)for循環(huán)提示unexpected token問題
這篇文章主要介紹了idea中增強(qiáng)for循環(huán)提示unexpected token問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Java數(shù)組常用排序算法實(shí)例小結(jié)
這篇文章主要介紹了Java數(shù)組常用排序算法,結(jié)合實(shí)例形式總結(jié)分析了java數(shù)組常用的4種排序算法,包括冒泡排序、數(shù)組遞增排序、快速排序及選擇排序,需要的朋友可以參考下2017-12-12

MyBatis?Generator生成的$?sql是否存在注入風(fēng)險(xiǎn)詳解

JAVA中的final關(guān)鍵字用法實(shí)例詳解