资讯专栏INFORMATION COLUMN

Java Optional 实践

jaysun / 3426人阅读

摘要:实践很简单的一个类,点开它的源代码,其中所有的方法都是与相关联的。从而很好地避免了空指针异常。方法,如果存在,返回包含的值,否则抛出异常。随便点开一个方法,都会在第一行为不该为的参数进行判断。

问题描述

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

实践 Optional

很简单的一个类,点开它的源代码,其中所有的方法都是与null相关联的。

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

它就是一个容器,其中有我们想要的对象,但是该对象有时候会是空,所以我们需要使用Optional封装好的方法来获取需要的对象。从而很好地避免了空指针异常。

错误示范

我看到网上很多人这么写:

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;
}

为什么不能再全局中处理呢?大家可以思考一下:

因为NoSuchElementException覆盖的范围太广了,只要是Optional中有null就会抛出NoSuchElementException,很多情况下都会造成这种异常,那我们究竟要给用户一个什么样的提示信息好呢?最后还是给出500服务器异常,那异常处理的意义何在呢?

所以我们需要用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方法。

orElseThrow方法,如果存在,返回包含的值,否则抛出异常。

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

所以传一个lamda表达式进去,然后IDEA会给出警告:

Can be replaced with method reference

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

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

异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {

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

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

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

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

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

一劳永逸

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

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

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

NotNull

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

如果你在Spring的项目中打过断点调试的话,那我断定你一定见过下面这行代码:

Assert.notNull();

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

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

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

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

总结

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77239.html

相关文章

  • Java 8th 函数式编程:Optional 类型

    摘要:当满足条件时执行传入的参数化操作。最后提醒一点,好用但不能滥用,在设计一个接口方法时是否采取类型返回需要斟酌,一味的使用会让代码变得比较啰嗦,反而破坏了代码的简洁性。鉴于作者水平有限,文中不免有错误之处,欢迎批评指正个人博客 NullPointException 可以说是所有 java 程序员都遇到过的一个异常,虽然 java 从设计之初就力图让程序员脱离指针的苦海,但是指针确实是实际...

    RayKr 评论0 收藏0
  • Java8新特性总览

    摘要:新特性总览标签本文主要介绍的新特性,包括表达式方法引用流默认方法组合式异步编程新的时间,等等各个方面。还有对应的和类型的函数连接字符串广义的归约汇总起始值,映射方法,二元结合二元结合。使用并行流时要注意避免共享可变状态。 Java8新特性总览 标签: java [TOC] 本文主要介绍 Java 8 的新特性,包括 Lambda 表达式、方法引用、流(Stream API)、默认方...

    mayaohua 评论0 收藏0
  • Java8实战》-第十章笔记(用Optional取代null)

    摘要:是第一批在堆上分配记录的类型语言之一。实际上,的这段话低估了过去五十年来数百万程序员为修复空引用所耗费的代价。很明显,这种方式不具备扩展性,同时还牺牲了代码的可读性。是目前程序开发中最典型的异常。完成这一任务有多种方法。 用Optional取代null 如果你作为Java程序员曾经遭遇过NullPointerException,请举起手。如果这是你最常遭遇的异常,请继续举手。非常可惜,...

    flybywind 评论0 收藏0
  • [译] Java 中最常见的 5 个错误

    摘要:近日,在上列举了开发中常见的个错误,与君共免。在多线程中并发修改集合内容是非常常见的,因此需要使用并发编程中常用的方法进行处理,例如同步锁对于并发修改采用特殊的集合等等。在单线程和多线程情况下解决这个问题有微小的差别。 在编程时,开发者经常会遭遇各式各样莫名错误。近日,Sushil Das 在 Geek On Java上列举了 Java 开发中常见的 5 个错误,与君共「免」。 原文...

    chemzqm 评论0 收藏0
  • Java Optional API

    摘要:于是,在引入了,用来代表一种可能有可能没有的数据,可以用来缓解空指针异常的问题。 一位智者说过,没有处理过空指针异常就不算一个真正的 Java 程序员。这当然是开玩笑,但是空指针异常确实是很多程序出错的源头。于是,在 Java 8 引入了 java.util.Optional,Optional 用来代表一种 可能有可能没有 的数据,可以用来缓解空指针异常的问题。 简单地说,Option...

    YorkChen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<