ResponseEntity<CommonResponseDTO> commonResponseDto = testClient.getCategoryById(sampleEntity.getCategoryId());
if(Objects.nonNull(commonResponseDto) && Objects.nonNull(commonResponseDto.getBody()) && Objects.nonNull(commonResponseDto.getBody().getName())){
SuperDataDto superDataCategoryDto = SuperDataDto.builder().id(sampleEntity.getCategoryId()).name(commonResponseDto.getBody().getName()).build();
在上面的代码中,SonarQube 抱怨说
A "NullPointerException" could be thrown; "getBody()" can return null. on
.name(commonResponseDto.getBody().getName())
我什至正在检查
nonNull
是否有commonResponseDto.getBody().getName())
。我是不是做错了什么?
SonarQube 是对的。
if(Objects.nonNull(commonResponseDto)
&& Objects.nonNull(commonResponseDto.getBody())
&& Objects.nonNull(commonResponseDto.getBody().getName())) {
SuperDataDto superDataCategoryDto = SuperDataDto.builder().id(sampleEntity.getCategoryId()).name(commonResponseDto.getBody().getName()).build();
不保证连续调用的
getBody()
的返回值。这是一个很容易使您的条件抛出的实现:
private int calls = 0;
public Body getBody() {
++calls;
if (calls % 2 == 0) return null;
return new Body(...);
}
第一次检查是非空的,第二次调用它将返回空并且你的代码会抛出异常。不要依赖方法从多个调用返回相同的引用,如果您需要单个值,请明确它并将其存储在局部变量中:
if (Objects.nonNull(commonResponseDto)) {
final CommonResponseDTO body = commonResponseDto.getBody();
if (Objects.nonNull(body)) {
final String name = body.getName();
if (Objects.nonNull(name)) {
SuperDataDto superDataCategoryDto = SuperDataDto.builder()
.id(sampleEntity.getCategoryId())
.name(name)
.build();
请注意,
Objects#nonNull
主要用作 lambda 表达式中的方法引用,如果您简单地编写 obj != null
,您的代码可能会更清晰。
但这很快就会变得丑陋。您可以通过将代码移至一个小的辅助函数来提高代码的清晰度:
private static String nameOfResponse(
final ResponseEntity<CommonResponseDTO> response) {
if (response == null) return null;
final CommonResponseDTO body = commonResponseDto.getBody();
if (body == null) return null;
return body.getName();
}
// ...
final String name = nameOfResponse(commonResponseDto);
if (name != null) {
final SuperDataDto superDataCategoryDto = SuperDataDto.builder()
.id(sampleEntity.getCategoryId())
.name(name)
.build();
}
有一点开销的替代方案是将对象包装在
Optional
中,然后转换此可选值:
Optional.ofNullable(commonResponseDto)
.map(CommonResponseDTO::getBody)
.map(Body::getName())
.ifPresent(name -> {
SuperDataDto superDataCategoryDto = SuperDataDto.builder()
.id(sampleEntity.getCategoryId())
.name(name)
.build();
});