Java Optional 实践

问题描述

在大热的Spring Boot 2.0中,在将原来的泛型改成了Optional,旨在让咱们的代码更简洁。java

clipboard.png

实践

Optional

很简单的一个类,点开它的源代码,其中全部的方法都是与null相关联的。程序员

clipboard.png

这是一个简化咱们处理null的类。spring

它就是一个容器,其中有咱们想要的对象,可是该对象有时候会是空,因此咱们须要使用Optional封装好的方法来获取须要的对象。从而很好地避免了空指针异常。服务器

clipboard.png

错误示范

我看到网上不少人这么写:框架

catRepository.findById(id).get();

下面是Spring Boot 1.5的写法,那请问:若是上面的写法是正确的,那为何还要大费周章设计一个Optional呢?函数

catRepository.findOne(id);

分析

经过get是能获取到咱们须要的对象。单元测试

可是看看get的源代码,这样写,抛出了NoSuchElementException异常,这个异常咱们无法在全局中处理它。测试

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

为何不能再全局中处理呢?你们能够思考一下:this

由于NoSuchElementException覆盖的范围太广了,只要是Optional中有null就会抛出NoSuchElementException,不少状况下都会形成这种异常,那咱们究竟要给用户一个什么样的提示信息好呢?最后仍是给出500服务器异常,那异常处理的意义何在呢?spa

因此咱们须要用Optional来抛出一个有特定范围的能被全局准确处理的异常。

Cat cat = catRepository.findOne(id);
if (null == cat) {
    throw new EntityNotFoundException("该实体找不到");
}
return cat;

思想都是同样,咱们不过是用一种更简洁的写法实现上面的功能。

实现

没错,就像下面同样,咱们只须要一行代码!

public Cat findById(Long id) {
    return catRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}

findById返回一个Optional,而后调用该对象的orElseThrow方法。

clipboard.png

orElseThrow方法,若是存在,返回包含的值,不然抛出异常。

该方法的参数是一个lamda表达式。这里就不深究lamda表达式的几种类型了,若是感兴趣能够自行研究下FunctionConsumerPredicateSupplier这四个函数式接口的区别。

clipboard.png

因此传一个lamda表达式进去,而后IDEA会给出警告:

clipboard.png

Can be replaced with method reference

lamda表达式能被一个方法引用代替,Alt + Enter,咱们最终的代码就长这样:

clipboard.png

这里的::lamda表达式的一种简写,是Java8中的新特性,看着可能有点奇怪,原来,编译器比程序员聪明多了。

异常处理

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(EntityNotFoundException.class)
    public ResponseEntity<String> entityNotFoundHandler() {
        return new ResponseEntity<>("您要找的实体不存在", HttpStatus.NOT_FOUND);
    }
}

写个控制器加强,全局处理异常,这里的RestControllerAdvice又是一个组合注解:

clipboard.png

处理异常,同时以Json的格式返回。

@Test
public void findById() throws Exception {
    this.mockMvc.perform(get("/cat/1"))
            .andDo(print());
}

写个控制器的单元测试,查询一个不存在的实体,运行,看控制台的打印输出:

clipboard.png

一劳永逸

一劳永逸,这是咱们最喜欢的东西了。

return catRepository.findById(id).orElseThrow(EntityNotFoundException::new);

之后再查询,就这一行,不再用去判断null了。

NotNull

正所谓条条大路通罗马,对null的一劳永逸,咱们这样实现,别人也能够那样实现。

若是你在Spring的项目中打过断点调试的话,那我判定你必定见过下面这行代码:

Assert.notNull();

如下是该方法的源码,注意这里的Assertorg.springframework.util包下的:

clipboard.png

刚方法用于判断null,若是为空,则抛出异常。

随便点开一个方法,都会在第一行为不应为null的参数进行判断。

clipboard.png

这里,不由对整个框架肃然起敬。

总结

以前一直抱怨Java更新的太快:

clipboard.png

其实,Java的每次更新,都是为了咱们更简洁优雅的代码而努力。去看看官方的描述,Java让咱们将更多的精力放在think上,而不是code上。

相关文章
相关标签/搜索