Java Optional实践(小结)

问题描述

在大热的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<String> 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的参数进行判断。

这里,不禁对整个框架肃然起敬,同样一个方法,大牛写了二十分钟,而你写了十分钟,但是你却去改了半个小时的bug

@Nullable

可能在上面看到了我们不熟悉的注解@Nullable,表示从来没见过,这个注解干什么用的呢?

万能的StackOverflow又给出了完美的回答:

这会让你的代码更清晰,如果你重写这个方法,你也需要让参数可为空。通常也用于代码提示。

@Nullable@NotNull这一对注解,没什么实际意义,只是用于代码更清晰,同时编译器能给出我们提示。

总结

之前一直抱怨Java更新的太快,学校教的是Java5之前的东西,从Java5开始有的注解,但是从来没讲过这个东西,然而去看看官方的描述:

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java8中新特性Optional、接口中默认方法和静态方法详解

    前言 毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本.这个版本包含语言.编译器.库.工具和JVM等方面的十多个新特性. Java 8是Java的一个重大版本,有人认为,虽然这些新特性领Java开发人员十分期待,但同时也需要花不少精力去学习.下面本文就给大家详细介绍了Java8中新特性Optional.接口中默认方法和静态方法的相关内容,话不多说了,来一起看看详细的介绍吧. Optional Optional 类(java.util.Optional) 是一个

  • Java8中Optional的一些常见错误用法总结

    前言 Java 8 引入的 Optional 类型,基本是把它当作 null 值优雅的处理方式.其实也不完全如此,Optional 在语义上更能体现有还是没有值.所以它不是设计来作为 null 的替代品,如果方法返回 null 值表达了二义性,没有结果或是执行中出现异常. 在 Oracle  做  Java 语言工作的  Brian Goetz 在 Stack Overflow 回复 Should Java 8 getters return optional type? 中讲述了引入  Opti

  • 利用Java8 Optional如何避免空指针异常详解

    前言 空指针是我们最常见也最讨厌的异常,为了防止空指针异常,你不得在代码里写大量的非空判断. Java 8引入了一个新的Optional类.用于避免空指针的出现,也无需在写大量的if(obj!=null)这样的判断了,前提是你得将数据用Optional装着,它就是一个包裹着对象的容器. 都说没有遇到过空指针异常的程序员不是Java程序员,null确实引发过很多问题.Java 8中引入了一个叫做java.util.Optional的新类可以避免null引起的诸多问题. 我们看看一个null引用能导

  • Java如何使用Optional与Stream取代if判空逻辑(JDK8以上)

    通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作. 注:如果对Java8新特性中的lambda表达式与Stream不熟悉的可以去补一下基础,了解概念. 首先下面代码中的List放入了很多Person对象,其中有的对象是null的,如果不加校验调用Person的getXXX()方法肯定会报空指针错误,一般我们采取的方案就是加上if判断: public class DemoUtils { public static void main(

  • JAVA Optional类用法分享

    Optional在JAVA中被定义为一个容器类,更确切的说只存一个元素的容器. container object which may or may not contain a non-null value. Optional类结构 Optional属性 Optional类中包含两个属性: 类属性:EMPTY 对象属性:value EMPTY属性用来存放一个value为null的Optional对象. value属性用来存放非null对象. Optional方法 Optional的有两个构造方法,

  • java8中forkjoin和optional框架使用

    并行流与串行流 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API 可以声明性地通过 parallel()与 sequential()在并行流与顺序流之间进行切换. 了解 Fork/Join 框架 Fork/Join 框架:就是在必要的情况下,将一个大任务,进形拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运行的结果进行join汇总. Fork/Join 框架

  • JAVA8如何妙用Optional解决NPE问题详解

    引言 NPE(NullPointerException)是调试程序最常见的异常.google一下有很多关于方法到底应该返回null还是new一个空对象的讨论. 在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示 在这种情况下,有如下代码 user.getAddress().getProvince(); 这种写法,在user为null时,是有可能报NullPointerException异常的

  • Java函数式开发 Optional空指针处理

    摘要 空闲时会抽空学习同在jvm上运行的Groovy和Scala,发现他们对null的处理比早期版本Java慎重很多.在Java8中,Optional为函数式编程的null处理给出了非常优雅的解决方案.本文将说明长久以来Java中对null的蹩脚处理,然后介绍使用Optional来实现Java函数式编程. 那些年困扰着我们的null 在Java江湖流传着这样一个传说:直到真正了解了空指针异常,才能算一名合格的Java开发人员.在我们逼格闪闪的java码字符生涯中,每天都会遇到各种null的处理,

  • Java函数式编程(六):Optional

    选取单个元素 直觉来说选取单个元素肯定会比选取多个要简单得多,不过这里也存在一些问题.我们先看下一般的做法的问题是什么,然后再看下如何用lambda表达式来解决它. 我们先新建一个方法来查找一个以特定字母开头的元素,然后打印出来. 复制代码 代码如下: public static void pickName( final List<String> names, final String startingLetter) { String foundName = null; for(String

  • 使用Java8中Optional机制的正确姿势

    前言 Java8带来的函数式编程特性对于习惯命令式编程的程序员来说还是有一定的障碍的,我们只有深入了解这些机制的方方面面才能运用自如.Null的处理在JAVA编程中是出了try catch之外的另一个头疼的问题,需要大量的非空判断模板代码,程序逻辑嵌套层次太深.尤其是对集合的使用,需要层层判空. 首先来看下Optional类的结构图: 而如果我们对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了 Optional<User

随机推荐