Java 8 给我们更好的消灭空指针解决方案

news2024/11/16 3:48:05

前言

大家好,在平时的业务开发中,空指针是我们经常遇到的问题,

他可能会导致我们的流程无法正常进行或者一些意外情况的发生。

这就是我们需要避免空指针的原因,那我们有哪些方式去解决这个问题呢?

空指针场景

  1. 包装类型字段,因为自动拆箱出现空指针;

  2. A对象包含B对象,通过A对象获取B对象字段时,没有判断就直接去调用B对象中的方法出现空指针;

  3. 字符串比较,null.equal("字符串")出现空指针

  4. 远程返回的List不是空数组而是null,对其进行操作出现空指针。

线上空指针问题如何排查

日常的开发过程中,一般情况下我们都是通过查看日志来排查空指针的问题,如果日志没有做到位的情况下,我们只能通过NullPointerException抛出的位置去跟踪代码。

这就要求我们,在写代码的时候做好日志的打印

  1. 调用方法的入口进行入参的打印,方法返回的结果进行出参打印

如果没有提前做好日志打印,那我们可以考虑利用阿里的Java诊断工具Arthas来处理

  1. Arthas启动后,获取来了JVM进程

  2. 通过watch指令来监测方法的入参情况

思考

对于这个问题,我总结了一些我在工作中使用到的方法,

最直接的操作都是从根源上消灭出现空指针的可能性,进行先判空再操作。

下面拿商品信息作为一个例子,我们要得到他店铺的名称,你会怎么写

@Data public class ProductVO implements Serializable { @ApiModelProperty("skuId") private Long skuId; @ApiModelProperty("商品名称") private String name; @ApiModelProperty("品牌名") private String brandName; @ApiModelProperty("库存") private Integer quantity; @ApiModelProperty("小图列表") private List<String> smallImgUrls; @ApiModelProperty("店铺信息") private ShopVO shop; 复制代码
  1. 防御性检查,每一个变量都做一次null检查,每一次不确定一个变量是否为null时,都需要添加一个嵌套的if块,这增加了代码的层数。

// 获取店铺名称 private String getShopName1(ProductVO productVO){ if (productVO != null){ ShopVO shop = productVO.getShopVO(); if (shop != null){ return shop.getName(); } } return ""; } 复制代码
  1. 快速失败检查,每一个null检查都是一个退出点,都返回一个固定的字符串,但是不能避免的是,忘记对某一个变量的检查。

// 获取店铺名称 private String getShopName2(ProductVO productVO){ String result = ""; if (Objects.isNull(productVO)){ return result; } ShopVO shop = productVO.getShopVO(); if (Objects.isNull(shop)){ return result; } return shop.getName(); } 复制代码
  1. 人为控制,对数据进行严格的控制,不能存在非空字段,但是不能很难保证所有数据都是正常的数据

  2. 利用Java8中的optional来做控制,对缺失的值建模,变量存在时对类进行简单的封装,不存在时,缺失的值会被建模成一个空的Optional对象

private static String getName4(ProductVO productVO){ return Optional.ofNullable(productVO).flatMap(data -> Optional.ofNullable(shopVO.getShopVO())) .map(ShopVO::getName).orElse(""); } 复制代码
  1. 创建一个Optional封装的ProductVO对象

  2. 将Optional转换为Optional

  3. 利用map,将Optianal转换为Optional

  4. 调用链上的任何一个方法,返回一个空,那么结果就是我们设置的默认值

​上面的几种方法中,我们看到了第四种方法,只用了一行代码就帮我们实现了消灭空指针的动作,但是Java 8中的 Optional 需要结合多个的方法来使用他,现在网上已经有很多详细方法文章,就不再做过多的介绍。

注意flatMap 与 Map 的区别

对于Stream流的运算中,flatMap 与 Map是我们常使用到的方法,很多人都没有搞清楚他们的差别是什么。

map(): map对列表中的每个元素应用一个函数,返回应用后的元素所组成的列表。

flatMap(): flatMap是一种常用的组合子,结合映射[mapping]和扁平化[flattening]。 flatMap需要一个处理嵌套列表的函数,然后将结果串连起来。

举个例子,一眼看出他们的区别

List<String> list = Arrays.asList("北京 天安门", "上海 东方明珠", "厦门 鼓浪屿"); //flatMap方法 list.stream().flatMap(item -> Arrays.stream(item.split(" "))).collect(Collectors.toList()).forEach(System.out::println); //结果: 北京 天安门 上海 东方明珠 厦门 鼓浪屿 // Map方法 list.stream().map(item -> Stream.of(item.split(" "))).forEach(System.out::println); // java.util.stream.ReferencePipeline$Head@6576fe71 // java.util.stream.ReferencePipeline$Head@76fb509a // java.util.stream.ReferencePipeline$Head@300ffa5d 复制代码

我们可以看到他们结果差异是非常大的

Map方法将list转换为了三个小的List对象的结果集

FlatMap方法的操作就是比Map方法的基础上,多做了一个扁平化[flattening]操作,将结果转化成一级结构,将里面的结果都取出来。

实践

List<ProductRespDTO> list = productVOList.getList().stream().map(d -> { return ProductRespDTO.builder().drugEncode(d.getSkuId()).drugName(d.getName()) .price(BigDecimal.valueOf(d.getPrice()).divide(new BigDecimal("100"))).usage(d.getUseMethod()) .imgUrl(d.getSmallImgUrls().stream().findFirst().orElse(null)).build(); 复制代码

这个例子中是否会存在空指针问题呢,如果是你你会怎么去修改?

总结

对于空指针问题,看起来问题不大,但是影响到了线上的业务正常运转,那肯定是不行的。

我们一定要有很清晰的思路去解决这个问题

  1. 事前,

  2. 一定要做好日志的打印工作,为了更方便的排查问题;

  3. 在实现业务逻辑的时候,如果你对你操作的对象不是很确定,那一定要先判空后操作;

  4. 针对于字符串类型的空指针我们可以采用Objects来做对比;

  5. 必填字段的入参校验

  6. 事中,事情既然已经发生了,那需要我们快速的通过日志和Arthas工具来定位问题,快速修复上线减少故障发生的时间:

  7. 事后,我们可以加强code review来审查自己的代码,避免这类情况的再次发生。

大家可以分享一下,自己平时遇到空指针是如何处理的~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux系统安装DB2数据库的详细步骤

1、DB2数据库的安装 一、将DB2的安装介质上传至/home目录&#xff0c;并解压&#xff1a; tar –zxvf v9.5fp3_linuxx64_server.tar.gz 二、执行LANGC 三、进入解压后的server目录&#xff08;cd server/&#xff09;&#xff0c;执行./db2setup,步骤如下&#xff1a; # cd…

数据结构-线性表与链性表(二)

目录 一、学习背景 二、简绍 三、线性表 一、什么是线性表 二、操作 1、插入 2、删除 3、查询 三、数组应用案例中源码分析 1、插入 2、删除 3、get与set 4、扩容 二、单向链表 单向链表结构 循环链表 三、数组和链表比较 1、时间复杂度角度 2、其他维度 3、…

【JS】原生js实现矩形框的绘制/拖动/缩放

1、要点及功能描述 通过js监听mouse事件来实现矩形框的绘制&#xff0c;再通过区分点击的是边角还是其他位置来实现矩形框的缩放和拖动&#xff0c;并且在拖动和缩放时&#xff0c;都做了边界限制&#xff0c;当缩放或拖动 到边界时&#xff0c;就不能继续拉缩放拖动了。当然在…

【个人简介】一枚在上海的AndroidiOSWindow逆向电子工程师

> Hello World!, I am Humenger 「 From Shanghai, China 」 「 Android Reverse engineer, applied electronic technology Shan Dong University, China 」 &#x1f41d;主要涉及平台: Android(70%),iOS(15%),Window(5%),macOS(3%),其他(7%) &#x1f98b;主要涉…

易基因|RNA m7G甲基化测序(m7G-MeRIP-seq)

N7-甲基鸟苷&#xff08;N7-methylguanosine&#xff0c;m7G&#xff09;是真核生物tRNA、rRNA和mRNA 5cap中最丰富的修饰之一。作为一种重要的表观遗传修饰&#xff0c;m7G RNA甲基化在基因表达、加工代谢、蛋白质合成、转录稳定等方面发挥着重要的作用&#xff0c;参与疾病发…

Pinely Round 1 (Div. 1 + Div. 2) E - Make It Connected思维分类讨论

昨晚的problem e 一直wa。因为答案&#xff0c;不唯一&#xff0c;调起来只能肉眼debug。被干emo了qwq。好在赛后看到 ugly2333的 思路和我差不多&#xff0c;最后还是要选取度数较小的最优, 好像从度数的角度出发&#xff0c;不容易wa。 题意&#xff1a; 给你一个图&#xf…

什么是组织孤岛?它会带来哪些影响?可以这样去对付它

作为一个在不同地点和时区与不同团队合作的远程工作者&#xff0c;我有过公平的孤岛经历。 是的&#xff0c;它们扼杀了任何组织的成长。那么&#xff0c;在使你&#xff08;和组织中的每个人&#xff09;失去生产力、困惑、自私和不快乐之后。 在这篇文章中&#xff0c;我将…

ADRV9009中armBinary反汇编IDA参数设置

armBinary.bin文件如果不做处理的话就是一堆16进制数,扔到IDA里也只是一堆有颜色的16进制数,需要进行一些参数设置。 1 选择IDA32位打开armBinary.bin文件 2 load a new file设置 Processor type选择ARM Little-endian [ARM],点击Edit ARM architecture options进行相应修…

Linux 中的内部命令和外部命令

Linux 中的内部命令和外部命令 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;Linux 中的内部命令和外部命令 CSDN&#xff1a;Linux 中的内部命令和外部命令 什么是 bash shell ? bash shell&#xff0c;就是一个程序&#xff0c;就是 Linux 系统安装的…

漫谈 Java 平台上的反应式编程

反应式编程&#xff08;Reactive Programming&#xff09;是一套完整的编程体系&#xff0c;既有其指导思想&#xff0c;又有相应的框架和库的支持&#xff0c;并且在生产环境中有大量实际的应用。在支持度方面&#xff0c;既有大公司参与实践&#xff0c;也有强大的开源社区的…

【Linux】-- 开发工具yum、vim、gcc、g++、gdb、make、makefile使用介绍

目录 一、yum 1.了解yum &#xff08;1&#xff09;RPM &#xff08;2&#xff09;yum 2.yum使用 &#xff08;1&#xff09;查看软件包 &#xff08;2&#xff09;安装软件 &#xff08;3&#xff09;卸载软件 二.Linux编辑器-vim 1. vim概念 &#xff08;1&am…

flink集群搭建

1、安装包flink-1.10.0-bin-scala_2.11.tgz 2、tar -zxf flink-1.10.0-bin-scala_2.11.tgz 解压到指定目录 解压之后的文件名称是flink-1.10.0 3、flink-1.10.0的目录结构如下&#xff1a; bin/&#xff1a;flink的相关命令 conf/&#xff1a;flink的配置文件 examples/&a…

业务数据分析-Excel公式与函数(三)

目录 概念 运算符 地址的引用 逻辑函数 文本函数 统计函数 查找与引用函数 日期函数 常见出错信息 概念 公式&#xff1a;Excel的核心功能&#xff0c;功能强大 如果要定义的话&#xff0c;可以说是 以开头的&#xff0c;对地址进行引用的计算形式 说的高大上一点的…

方法2—并行数据流转换为一种特殊串行数据流模块的设计

并行数据流转换为一种特殊串行数据流模块的设计&#xff0c;设计两个可综合的电路模块1&#xff0c;第一个可综合模块&#xff0c;M1。2&#xff0c;描述M2模块3&#xff0c;描述M0模块的Verilog代码4&#xff0c;描述顶层模块5&#xff0c;电路生成的门级网表&#xff0c;netl…

Camtasia2023简单易用的电脑录屏视频剪辑软件

教学、演示、培训视频轻松制作!Camtasia非常容易学习 你不需要一个大的预算或花哨的视频编辑技能。只需录制屏幕并添加一些特效即可。无论您是有经验还是这是第一次制作视频 Camtasia都会为您提供制作高质量视频所需的一切。创建观看者实际观看的内容。视频将为您提供更多的互动…

军队文职丨2022年武警部队面向社会公开招聘351名文职人员公告!高中学历可报,11月25日前报名!

2022年武警部队面向社会公开招聘 专业技能岗位文职人员公告 根据《军队专业技能岗位文职人员聘用管理暂行规定》及有关政策规定&#xff0c;现就2022年武警部队面向社会公开招聘专业技能岗位文职人员有关事项公告如下&#xff1a; 一、招聘岗位 武警部队所属用人单位运输投送…

前后端分类 (增加,查询)

目录 一&#xff0c;后台代码 二&#xff0c;前台代码 一&#xff0c;后台代码 一&#xff0c;配置文件 application.yml server:port: 8080servlet:context-path: /spboot spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.j…

隧道HTTP API使用教程

华科隧道HTTP格式为&#xff1a;ip:port username password 隧道代理分钟2种模式&#xff1a; 固定时间更改新IP&#xff08;比如5分钟&#xff0c;10分钟&#xff0c;初次开通的时候可设定&#xff09;请求一次更换一个新IP&#xff08;可通过浏览器或者curl&#xff09; 1、…

图_图的存储_添加边_图的遍历_DFS_树的重心_BFS_图中点的层次

文章目录图有向图的存储添加遍历1.DFS例题&#xff1a;树的重心题目分析使用DFS遍历2.BFS例题&#xff1a;图中点的层次图 树是特殊的图&#xff08;无环连通图&#xff09; 有向图&#xff08;a -> b&#xff09; 无向图&#xff08;a -> b, b -> a&#xff09; …

ffmpeg源码阅读之avformat_alloc_output_context2

整体结构流程 核心逻辑 通过读源码发现核心的处理逻辑是av_guess_format函数&#xff0c;这里就根据核心逻辑来阅读&#xff0c;其余的基本是是在做判断和赋值 av_guess_format阅读分析 步骤1(先看头文件) /*** Return the output format in the list of registered output…