Java回調函數
Java中回調是什么
Java函數回調,也許說的這么專業你并不知道它是干嘛,有啥用。實際上你都有用過,比如多線程的Thread接口就是最典型的例子,當你調用start()函數時,就會觸發run()函數。
??回調就是:A調用B,讓 B 取處理某件事,然后 A 去忙其他的事情,B 處理完成之后再調用 A ,告訴 A 事情處理的結果
調用
- 同步調用:同一時間只能做一件事
- 異步調用:同一時間可以做多件事,一般通過以下兩種手段實現:
- 多線程:為需要阻塞的方法單獨啟動一個線程執行
- 回調:執行完成后通過回調,通知主線程執行完畢或者獲取執行結果
java 回調
1??基本回調
A <--> B
A對象 ----B.fb(A) -----> B對象 // 調用B的fb()時傳入A本身(this)
B對象(fb 方法)----->A.fa()------>A對象 // B就可以直接調用A,fa()就是回調方法
2??接口回調
基于接口回調:若只能給fb()傳入A類型那么就是強耦合,所以一般給 fb() 傳入的是一個接口,A實現這個接口
A <--> B
AImpl ----B.fb(IA) -----> B對象 // IA是接口,AImpl是IA的實現類
B對象(fb 方法)------>IA.fa()----->AImpl
3??異步回調
異步回調就是給B.fb()方法單獨起一個線程去執行
- 使用場景:當A要調用B的某個方法,且該方法會產生阻塞,或耗時較長,則可以將該方法做成異步調用
- 異步通信:通過回調機制進行通信,執行完后告知A
AImpl ----B.fb(IA) -----> B對象 // B.fb(IA)單獨起一個線程執行
B對象(fb 方法)------>IA.fa()----->AImpl
代碼
概念說完了,下面就上代碼...
同步調用
碼農(Programmer)現在需要做幾件事情:
- 敲代碼一整天(敲代碼)
- 將今天工作代碼上傳到Github上(上傳代碼)
- 備注一下完成日期(記錄下完成的日期)
下面我們用程序去實現:程序一共就三個類:
- Programmer(碼農類)
- Github(Github類 用于保存碼農提交的代碼)
- TestDemo(用于測試并顯示結果)
如下所示:
public class Programmer {
public void code(){
System.out.println("coding"); //step1.寫代碼
new Github().push(); //step2.提交代碼
recordToday(); //step3. 記錄的日期
}
public void recordToday(){
System.out.println("i'm done " + new Date());
}
}
// 只負責上傳代碼
public class Github {
public void push(){
System.out.println("git push");
}
}
// 讓Programmer工作
public class TestDemo {
public static void main(String args[]){
Programmer p = new Programmer();
p.code();
}
}
執行結果如下:
基本回調
可否給苦逼程序員一條生路,讓他提交代碼之后就下班,像記錄日期:recodeToday()這種事讓Github類去負責。
換句話說,Github類的push()函數執行完后,Github類去調用Programmer類的recodeToday()方法,而不是Programmer自己去調用,略微改動后
// A
public class Programmer {
public void code(){
System.out.println("coding");
new Github().push(this); // B.fb(this)
// 這里沒有 step3,碼農沒有自己調用 recordToday()方法.
}
// A.fa(),回調方法
public void recordToday(){
System.out.println("i'm done " + new Date());
}
}
// B
public class Github {
public void push(Programmer p ){ // push的參數多了Programmer類
System.out.println("git push");
p.recordToday(); // 執行回調
}
}
最后執行結果不變
接口回調(可以結合 lambda)
如果現在不只有Programmer了還有Teacher和Student,那GitHub的push方法難道要再重載?最好的辦法是push依賴接口
// IA,回調接口
public interface RecodeInterface {
public void recode();
}
// B
public class Github {
public void push(RecodeInterface r ){ // 依賴接口
System.out.println("git push");
r.recode(); // A.fa(),執行回調
}
}
// AImpl,實現了接口
public class Programmer implements RecodeInterface{
public void code(){
System.out.println("coding");
new Github().push(this); // B.fb(A)
}
@Override
public void recode() { // 回調函數
System.out.println("Programmer done " + new Date());
}
}
public class Student {
public void code(){
System.out.println("coding");
new Github().push(new StudentRecodeToday());
}
// AImpl,也可以單獨抽象出一個內部類
public class StudentRecodeToday implements RecodeInterface{
@Override
public void recode() {
System.out.println("Student done "+ new Date());
}
}
}
?使用 lambda 表達式
public class Student {
public void code() {
System.out.println("coding");
new Github().push(() -> System.out.println("Student done " + new Date()));
}
// AImpl,也可以單獨抽象出一個內部類
// public class StudentRecodeToday implements RecodeInterface{
// @Override
// public void recode() {
// System.out.println("Student done "+ new Date());
// }
// }
}
異步回調
// IA,回調接口
public interface mycallback {
void onData(Object message); // 正常處理
void onError(Exception e); // 異常處理
}
// AImpl,實現了回到接口
public class Client implements mycallback{
int count=0;
@Override
public void onData(Object message) {
count++;
System.out.println("received message:"+message.toString());
}
@Override
public void onError(Exception e) {
System.out.println("error!");
}
public void send(String message){
// 異步回調核心!!! 為B.fb(IA)單獨啟動一個線程
Thread thread=new Thread(new Server(Client.this,message));
thread.start();
}
}
// B
public class Server implements Runnable{
mycallback c;
Object message;
public Server(mycallback cl,Object o){
c=cl;
message=o;
}
@Override
public void run() {
try {
c.onData(message+" after server"); // 執行回調
}catch (Exception e){
c.onError(e);
}
}
}
啟動類
public class Work{
public static void main(String[] args){
Client c1=new Client();
c1.send(hello);
System.out.println("do others...");
}
}
結果
do others...
received message:hello

浙公網安備 33010602011771號