准备代码如下
通用返回类
import lombok.Data;
import java.util.List;
/**
* @Description 通用返回类
* @Author seb's
* @Date Created in 2024/6/16 11:56
*/
@Data
public class Response {
private String returnDataTime;
private String serialNo;
private Body body;
// Getters and Setters
@Data
public static class Body {
private ResponseData responseData;
}
@Data
public static class ResponseData {
private List<Item> items;
}
@Data
public static class Item {
private String name;
}
}
最初的判空处理写法
List<ResponseList> query(Event event) {
ApiRequestEvent apiRequestEvent = buildEvent(event);
log.info("接口入参:{}", JSONObject.toJSONString(apiRequestEvent));
CommonResponse<ApiRequestResponse> resonponse = apiClient.request(apiRequestEvent);
log.info("接口出参:{}", JSONObject.toJSONString(apiRequestEvent));
checkCommonResponse(resonponse);
JSONArray items = Optional.ofNullable(resonponse.getBody())
.map(body -> body.getResponseData().getItems())
.map(JSONObject::toJSONString)
.map(JSONObject::parseArray)
.orElseGet(JSONArray::new);
if (items.isEmpty()) {
return Collections.emptyList();
}
return items.stream()
.map(item -> BeanUtil.toBean(item, ResponseList.class))
.collect(Collectors.toList());
}
分析
在代码Review的时候,同事负责任的告知我的代码只对getBody做了判空处理,而当responseData为空时getItems会出现空指针,Seb‘s自信的说:“Optional.ofNullable会对链式调用的代码逐个判空,然而周末对自己这个想法进行简单的psvm验证,发现Optional的级联调用判空的写法写错了,“逐个判空”纯属自己yy,明天过去第一件事检查一下代码是不是还是错的😂😂
正确的写法应该如下。
public static void main(String[] args) {
Response response = new Response();
// 2. 模拟body非null
// response.setBody(new Response.Body());
// 1. 模拟body为null
System.out.println(response);
JSONArray items = Optional.ofNullable(response.getBody())
.map(body -> body.getResponseData())//只有非空才会继续下面的代码,一旦为空会直接执行OrElseGet
.map(responseData -> responseData.getItems())
.map(JSONObject::toJSONString)
.map(JSONObject::parseArray)
.orElseGet(JSONArray::new);
/**
* 正确判空验证结果:
* 1. body为null,返回[]
* 2. body非null,responseData为null
*/
System.out.println(items);
}
当天在改sonar异味代码发现类似的问题在历史代码中也存在很多,优化的方案在alibaba代码规范中也有推荐使用方式,那就是用Optional对级联调用依次判空。