Java中的回调与Lambda表达式

2 篇文章 0 订阅
2 篇文章 0 订阅

Java回调与Lambda表达式

2019更新:Java8的lambda函数式编程也来于此,只是要求接口中必须有且只有一个抽象方法,并且有个专用注解@FunctionalInterface 用于声明该接口为函数式接口

回调函数一般也称钩子函数

可能很多人对回调不是很熟悉,特别是做后端业务开发的同学,其实回调很常见,当你这样创建一个线程的时候就已经用到了回调

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println();
    }
})
// 等价于lambda
new Thread(System.out::println);

我个人理解,在Java中回调就是多态的一种应用.

它一般通过接口,抽象类实现.

简单理解就是,你要调用的某个方法method_a有一个接口类型的参数Callback callbackmethod_a 方法内调用了callback内的方法method_b ,由于method_b 是抽象的,所以在你调用method_a的时候必须传一个Callback的实现类。当然你也可以不必专门去定义一个实现类,可以采用匿名内部类的方式(是不是有点绕?)

其实这样做的目的就是使代码更加灵活,可以在不同场景下定制化实现不同的处理逻辑,同时又能复用基础代码。


最常见的回调应用场景就是按钮事件处理,比如说setOnclicklistener这个方法(用来给按钮对象设置一个OnClickListener类型对象)

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //TODO handle event
    }
});
// 用lambda改写
btn.setOnClickListener(v -> {
	//TODO handle event
});

事件多种多样,每个事件触发之后要执行的操作是不确定的,这时候就可以给按钮对象设置一个简单接口OnClickListener类型对象,在OnClickListener里面我们定义一个方法onClick,我们规定这个onClick方法就是用来消费事件的,按钮对象在监听到事件的时候会调用OnClickListener.onClick 方法。

这样尽管事件多种多样,都可以统一使用onClick这个方法去处理,具体怎么处理就看具体的onClick实现代码。所以这个onClick方法就叫回调方法,所以把它叫做钩子函数。


回调还经常出现在客户端访问网络的时候,安卓中规定在主线程中不可以直接访问网络等耗时操作,你应该放在子线程中去执行。不然主线程很容易被阻塞,主线程一旦被阻塞。UI就会出现假死,严重影响用户体验。(超过5秒未响应系统会提示长时间未响应)

为了应对这样的场景,我们做一个工具类HttpUtil,定义一个访问网络的方法getData(),专门用来处理网络请求。对于每次请求,getData() 里创建一个线程去异步访问网络,这样主线程就不会被阻塞。

但是子线程什么时候执行完,返回一个什么样的结果,这也是不确定的。但总会有一个结果,要么OK,要么error,要么timeout,所以你总得想办法handle一下。

这就就可以用上面说的回调来做,先定义一个HttpCallBack接口,可以把他定义在HttpUtil内部,在CallBack里定义onResponse、onFailure方法。

再在getData的参数中,定义一个HttpCallBack类型参数。如下:

public interface HttpCallBack {
    void onResponse(JSONObject jsonObject);
    void onFailure(String errorMsg);
}

在子线程处理完请求拿到结果的时候调用onResponse、onFailure

这样一来,这个HttpUtil就是通用的了,你可以用他来下载一张图片,或者请求json数据。而你每次调用的时候都可以以匿名内部类方式实现HttpCallBack,在response里添加相应的数据处理逻辑,比如更新UI上的图片,解析得到的json数据并更新UI,或者在onFailure里弹出一个请求失败的提示对话框。

所以,在一些异步耗时操作或者需要定制化拓展的场景下回调比较常见。

Define:

public void getDate(List<Param> params, String url, final HttpCallBack httpCallBack) {
    //new Thread
    new Thread(new Runnable() {
        @Override
        public void run() {
            //send request
            //...
            {
                //if success
                httpCallBack.onResponse(json);
                //if failure
                httpCallBack.onFailure(errorMsg);
            }
        }
    }).start();
}

// lambda形式
public void getDate(List<Param> params, String url, final HttpCallBack httpCallBack) {
    //new Thread
    new Thread(() -> {
		//send request
		//...
		{
		    //if success
		    httpCallBack.onResponse(json);
		    //if failure
		    httpCallBack.onFailure(errorMsg);
		}
    }).start();
}

Use:

getDate(params, url, new HttpCallBack() {
    @Override
    public void onResponse(JSONObject jsonObject) {
    	// parse jsonObject, refresh UI
    }
    @Override
    public void onFailure(String errorMsg) {
		alert(errorMsg);
    }
});

注意:由于HttpCallBack 定义了两个抽象方法,不符合函数式接口的规定,无法用lambda改写!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值