Java中避免写嵌套if样式的代码详解

前言

Optional的代码相对更加简洁,当代码量较大时,我们很容易忘记进行null判定,但是使用Optional类则会避免这类问题。

下面这是一个嵌套的 if 判断,业务逻辑是从 httpRequst 中获取 X-Auth-Token 的值。逻辑是如果 header中有值则从 header 中取值否则从 cookie 中取值,取到值后调用一个 http 远程接口 获取用户信息,获取不到则报“获取用户信息失败”,如果 token 都不存在则直接返回 httpRespons 为 401-NoAuth

这下面是之前同事写的代码

if 嵌套代码

if (methodNeedAuth) {
 //***身份验证
 String token = request.getHeader("X-Auth-Token");
 if (StringUtils.isEmpty(token)) { // 如果 header 中没有 X-Auth-Token 则从 cookie 中取
 Cookie[] cookies = request.getCookies();
 if (cookies == null || cookies.length == 0) { //cookie 都为 null
  return returnNoAuthResult(response);
 } //这个地方判空,否则下面的 Arrays.stream 回报空指针异常
 token = Arrays.stream(cookies).filter(cookie ->
  "X-Auth-Token".equals(cookie.getName())
 ).collect(Collectors.toList()).get(0).getValue();
 if (token == null) { // cookie 有值但是 cookie 中没有 X-Auth-Token
  return returnNoAuthResult(response);
 }
 }
 if (!StringTool.isNullOrEmpty(token)) {
 userInfo = userService.getUserInfoByToken(token);
 }
 if (userInfo == null || StringTool.isNullOrEmpty(userInfo.getUser_id())) {
 return returnNoAuthResult(response);
 }
}

Optional 规避 if 嵌套

if (methodNeedAuth) {
 //***身份验证
 String token = Optional.ofNullable(request.getHeader("X-Auth-Token")).orElseGet(() ->
  getTokenFromCookie(request) //提取出一个方法
 );
 userInfo = Optional.ofNullable(token).map(Try.of(t ->
  userService.getUserInfoByToken(t))
 ).orElse(null);
 if (userInfo == null || StringTool.isNullOrEmpty(userInfo.getUser_id())) {
 response.sendError(401, "no auth");
 return false;
 }
}
/**
 * 从 cookie 中获取 token
 */
private String getTokenFromCookie(HttpServletRequest request) {
 Cookie[] cookies = Optional.ofNullable(request.getCookies()).orElse(new Cookie[0]); // Optional 强制赋默认值,cookies一定不为 null
 String cookie = Arrays.stream(cookies).filter(item ->
  "X-Auth-Token".equals(item.getName())
 ).findFirst().map(Cookie::getValue).orElse(null);
 return cookie;
}

小结

Java8 Optional 的常规用法

Java8 的 Optional 可以规避所有的空指针异常问题么?答案当然是否定的, Optional<T>() 也是对象,他也会为 null, 所以也有可能报空指针异常哟。

Optional 的三种构造方式: Optional.of(obj), Optional.ofNullable(obj) 和明确的 Optional.empty()

  • Optional.of(obj) : 它要求传入的 obj 不能是 null 值的, 否则还没开始进入角色就倒在了 NullPointerException 异常上了.
  • Optional.ofNullable(obj) : 它以一种智能的, 宽容的方式来构造一个 Optional 实例. 来者不拒, 传 null 进到就得到 Optional.empty() , 非 null 就调用 Optional.of(obj) .

那是不是我们只要用 Optional.ofNullable(obj) 一劳永逸, 以不变应二变的方式来构造 Optional 实例就行了呢? 那也未必, 否则 Optional.of(obj) 何必如此暴露呢, 私有则可?

我本人的观点是:

  • 当我们非常非常的明确将要传给 Optional.of(obj) 的 obj 参数不可能为 null 时, 比如它是一个刚 new 出来的对象(Optional.of(new User(…))) , 或者是一个非 null 常量时;
  • 当想为 obj 断言不为 null 时, 即我们想在万一 obj 为 null 立即报告 NullPointException 异常, 立即修改, 而不是隐藏空指针异常时, 我们就应该果断的用 Optional.of(obj) 来构造 Optional 实例, 而不让任何不可预计的 null 值有可乘之机隐身于 Optional 中.

Java8 Optional需要小心的地方

  • Reports calls to java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception. (调用 Optional.get() 前不事先用 isPresent() 检查值是否可用. 假如 Optional 不包含一个值, get() 将会抛出一个异常)
  • Reports any uses of java.util.Optional, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”. Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not. (使用任何像 Optional 的类型作为字段或方法参数都是不可取的. Optional 只设计为类库方法的, 可明确表示可能无值情况下的返回类型. Optional 类型不可被序列化, 用作字段类型会出问题的)

一句话小结: 使用 Optional 时尽量不直接调用 Optional.get() 方法, Optional.isPresent() 更应该被视为一个私有方法, 应依赖于其他像 Optional.orElse() , Optional.orElseGet() , Optional.map() 等这样的方法.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • 详解Java编程中if...else语句的嵌套写法

    if...else if...else语句 if语句后面可以跟elseif-else语句,这种语句可以检测到多种可能的情况. 使用if,else if,else语句的时候,需要注意下面几点: if语句至多有1个else语句,else语句在所有的elseif语句之后. If语句可以有若干个elseif语句,它们必须在else语句之前. 一旦其中一个else if语句检测为true,其他的else if以及else语句都将跳过执行. 语法 if...else语法格式如下: if(布尔表达式 1){

  • Java中避免写嵌套if样式的代码详解

    前言 Optional的代码相对更加简洁,当代码量较大时,我们很容易忘记进行null判定,但是使用Optional类则会避免这类问题. 下面这是一个嵌套的 if 判断,业务逻辑是从 httpRequst 中获取 X-Auth-Token 的值.逻辑是如果 header中有值则从 header 中取值否则从 cookie 中取值,取到值后调用一个 http 远程接口 获取用户信息,获取不到则报"获取用户信息失败",如果 token 都不存在则直接返回 httpRespons 为 401-

  • java 中枚举类enum的values()方法的详解

    java 中枚举类enum的values()方法的详解 前言: 关于枚举,相信使用的已经很普遍了,现在主要写的是枚举中的一个特殊方法,values(), 为什么说特殊呢,因为在Enum 的 API 文档中也找不到这个方法.接下来就看看具体的使用. 理论上此方法可以将枚举类转变为一个枚举类型的数组,因为枚举中没有下标,我们没有办法通过下标来快速找到需要的枚举类,这时候,转变为数组之后,我们就可以通过数组的下标,来找到我们需要的枚举类.接下来就展示代码了. 首先是我们自己的枚举类. public e

  • Java中关于二叉树的概念以及搜索二叉树详解

    目录 一.二叉树的概念 为什么要使用二叉树? 树是什么? 树的相关术语! 根节点 路径 父节点 子节点 叶节点 子树 访问 层(深度) 关键字 满二叉树 完全二叉树 二叉树的五大性质 二.搜索二叉树 插入 删除 hello, everyone. Long time no see. 本期文章,我们主要讲解一下二叉树的相关概念,顺便也把搜索二叉树(也叫二叉排序树)讲一下.我们直接进入正题吧!GitHub源码链接 一.二叉树的概念 为什么要使用二叉树? 为什么要用到树呢?因为它通常结合了另外两种数据结

  • java中的抽象类和接口定义与用法详解

    目录 一.抽象类 1.什么叫抽象类? 2.抽象类的特点: 3.成员特点: 二.接口 1.接口是什么? 2.接口的特点 3.接口的组成成员 4.类与抽象的关系: 5.抽象类与接口的区别: 一.抽象类 1.什么叫抽象类? 例如在生活中我们都把狗和猫归为动物着一类中,但当只说动物时,我们是不知道是猫还是狗还是其他的.所以动物就是所谓的抽象类,猫和狗则是具体的类了.因此在Java中,一个没有方法体的方法应该定义为抽象类,而类中有抽象方法,则必须为抽象类. 2.抽象类的特点: 抽象类与抽象方法必须用abs

  • Java中文件的读写方法之IO流详解

    目录 1.File类 1.1File类概述和构造方法 1.2File类创建功能 1.3File类判断和获取功能 1.4File类删除功能 2.递归 2.1递归 2.2递归求阶乘 2.3递归遍历目录 3.IO流 3.1 IO流概述和分类 3.2字节流写数据 3.3字节流写数据的三种方式 3.4字节流写数据的两个小问题 3.5字节流写数据加异常处理 3.6字节流读数据(一次读一个字节数据) 3.7字节流复制文本文件 3.8字节流读数据(一次读一个字节数组数据) 3.9字节流复制图片 总结 1.Fil

  • Java中读写锁ReadWriteLock的原理与应用详解

    目录 什么是读写锁? 为什么需要读写锁? 读写锁的特点 读写锁的使用场景 读写锁的主要成员和结构图 读写锁的实现原理 读写锁总结 Java并发编程提供了读写锁,主要用于读多写少的场景,今天我就重点来讲解读写锁的底层实现原理 什么是读写锁? 读写锁并不是JAVA所特有的读写锁(Readers-Writer Lock)顾名思义是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的. 所谓的读

  • Java实现手写线程池实例并测试详解

    前言 在之前的文章中介绍过线程池的核心原理,在一次面试中面试官让手写线程池,这块知识忘记的差不多了,因此本篇文章做一个回顾. 希望能够加深自己的印象以及帮助到其他的小伙伴儿们 在线程池核心原理篇介绍过线程池的核心原理,今天来模拟线程池和工作队列的流程,以及编写代码和测试类进行测试.下面附下之前线程池的核心流程: 在线程池核心原理的源码中,涉及到了一系列的流程,包括线程池队列数量是否已满,运用什么样的拒绝策略等.在我们手写线程池的代码中,不需要考虑那么多因素,只需要模拟简单的情景和过程,因此整体来

  • java 中mongodb的各种操作查询的实例详解

    java 中mongodb的各种操作查询的实例详解 一. 常用查询: 1. 查询一条数据:(多用于保存时判断db中是否已有当前数据,这里 is  精确匹配,模糊匹配 使用regex...) public PageUrl getByUrl(String url) { return findOne(new Query(Criteria.where("url").is(url)),PageUrl.class); } 2. 查询多条数据:linkUrl.id 属于分级查询 public Lis

  • java中 Set与Map排序输出到Writer详解及实例

     java中 Set与Map排序输出到Writer详解及实例 一般来说java.util.Set,java.util.Map输出的内容的顺序并不是按key的顺序排列的,但是java.util.TreeMap,java.util.TreeSet的实现却可以让Map/Set中元素内容以key的顺序排序,所以利用这个特性,可以将Map/Set转为TreeMap,TreeSet然后实现排序输出. 以下是实现的代码片段: /** * 对{@link Map}中元素以key排序后,每行以{key}={val

  • java 中基本算法之希尔排序的实例详解

    java 中基本算法之希尔排序的实例详解 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shell于1959年提出而得名. 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止. 基本思想:算法先将要排序的一组数按某个增量d(n/2,n为要排序数的个数)分成若干组,每组中记录的下标相差

随机推荐