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

news2024/12/22 20:01:49

前言

大家好,我是小郭。

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

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

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

空指针场景

  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. 事前,

    • 一定要做好日志的打印工作,为了更方便的排查问题;
    • 在实现业务逻辑的时候,如果你对你操作的对象不是很确定,那一定要先判空后操作;
    • 针对于字符串类型的空指针我们可以采用Objects来做对比;
    • 必填字段的入参校验
  2. 事中,事情既然已经发生了,那需要我们快速的通过日志和Arthas工具来定位问题,快速修复上线减少故障发生的时间:

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

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

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

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

相关文章

英语语法基础

英语语法知识点1   第一点&#xff1a;动词的变化   1、代词及be动词   主格 I we you you she/he/it they   宾格 me us you you her/him/it them   代词所有格 my our your your her/his/its their   名词性代词 mine ours yours yours hers/his/its theirs   …

FPGA数字信号、图像

1、基于FPGA的数字图像处理原理及应用 (牟新刚) 本书首先介绍FPGA程序设计和图像与视频处理的关键基础理论&#xff0c;然后通过实例代码详细讲解了如何利用FPGA实现直方图操作中的直方图统计/均衡化/线性拉伸/规定化、线性滤波器操作中的均值滤波器、Sobel算子(滤波、求模、求…

Redis从理论到实战:用Redis解决缓存穿透、缓存击穿问题(提供解决方案)

文章目录一、缓存穿透1、什么是缓存穿透2、解决方案二、缓存雪崩三、缓存击穿1、什么是缓存击穿2、解决方案3、互斥锁解决缓存击穿问题4、逻辑删除解决缓存击穿问题加油加油&#xff0c;不要过度焦虑(*^▽^*) 一、缓存穿透 1、什么是缓存穿透 缓存穿透是指客户端请求的数据在…

重组蛋白/细胞因子的实验操作

在我们进行抗体制备、ELISA、药物研究、免疫实验、细胞培养、晶体结构分析等实验时&#xff0c;免不了要和重组蛋白打交道。MCE 重组蛋白产品涵盖超过 2000 种不同功能的重组蛋白&#xff0c;具有批次间一致性&#xff0c;优异的活性以及极低的内毒素水平等特性&#xff0c;可用…

小学生python游戏编程arcade----坦克大战3

小学生python游戏编程arcade----坦克大战3前言整体解绍1、坦克大战3--未完&#xff0c;只是功能初具1.1 文件结构1.2 类1.3 角色类1.4 粒子类1.5 主程序框1.6 main函数1.7 效果图1.8 代码实现源码获取前言 接以上多篇文章解绍arcade游戏编程的基本知识&#xff0c;回归主题&am…

数商云B2B电商系统商品管理功能剖析,助力家用电器企业业务提效

如今&#xff0c;传统家用电器企业的发展空间不断受到电商渠道的积压&#xff0c;由于许多家电企业缺乏数字化的管理工具&#xff0c;导致管理低效&#xff0c;还很容易产生存货积压、供不应求等问题。随着家用电器市场需求疲软、竞争日趋白热化&#xff0c;家用电器企业亟须加…

密码学 数字签名

消息鉴别的缺陷 消息鉴别保证了数据完整性&#xff0c;消息不被第三方侵犯&#xff0c;但是不保证双方之间的欺骗。如果A发送认证消息给B&#xff0c;可能会存在多种争议&#xff1a; B伪造一个不同的消息&#xff0c;声称是A发的 A否认发过这个消息&#xff0c;B无法证明A确实…

爬虫软件是什么意思

爬虫软件的正宗名称是python计算机编程语言&#xff0c;广泛应用于系统管理任务的处理和Web编程。 python软件为什么叫爬虫软件&#xff1f;爬虫通常指的是网络爬虫&#xff0c;就是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。所以Python被很多人称为…

抗疫众志成城网页设计成品 抗击疫情感动人物网页制作模板 大学生抗疫静态HTML网页源码 dreamweaver网页作业致敬逆行者网页设计作品

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

缓存过期都有哪些策略?

常见以下四种缓存过期策略&#xff1a; 定时过期&#xff1a;每个设置过期时间的key都需要创建⼀个定时器&#xff0c;到过期时间就会立即清除。该策略可以⽴ 即清除过期的数据&#xff0c;对内存很友好&#xff1b;但是会占⽤⼤量的CPU资源去处理过期的数据&#xff0c;从⽽影…

C++11、17、20的内存管理-指针、智能指针和内存池从基础到实战(上)

C11、17、20的内存管理-指针、智能指针和内存池从基础到实战&#xff08;上&#xff09;第一章 指针原理和快速入门1、第一个指针程序-详解指针代码2、图示进程的内存空间划分分析代码区_堆栈_内核空间3、各种内存空间-堆_栈_全局地址代码演示4、图解堆栈空间分配对应的指针代码…

中学化学教学参考杂志社中学化学教学参考编辑部2022年第12期目录

教学论坛《中学化学教学参考》投稿&#xff1a;cn7kantougao163.com 探索有效问题的层次化设计和结构化布局 于滨; 1-5 “双减”政策下初中化学作业设计策略与方法探究 王洁; 5-7 中学化学课程思政教学案例设计 兰青;靳素娟;马玲;谢海泉; 8-9 化学教学情境创设…

5G无线技术基础自学系列 | 基础参数及帧结构

素材来源&#xff1a;《5G无线网络规划与优化》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 5G在空中接口的参数定义大多和LTE一致&…

Centos7 安装Seata1.5.1

一、环境说明 IP操作系统程序备注10.0.61.22centos7.9PostgreSQL-14.11已提前部署10.0.61.21centos7.9Nacos-2.1.0已提前部署10.0.61.22centos7.9seata-server-1.5.1本文将要部署 二、部署 1. 下载 wget https://github.com/seata/seata/releases/download/v1.5.1/seata-ser…

【Java八股文总结】之Spring MVC

文章目录Spring MVC1、Spring MVC介绍2、Spring MVC的核心组件3、Spring MVC工作流程4、Spring MVC Restful风格的接口的流程&#xff1f;5、Spring MVC请求参数的种类1. 请求参数&#xff08;传递json数据&#xff09;2. 日期类型参数传递6、Spring MVC开发中用到的工具7、Spr…

SRM采购管理系统投标管理模块:阳光招采,助力建筑材料企业智慧采购

在建筑行业企业材料管理的四大业务环节即采购、运输、储备和供应&#xff0c;采购是首要环节&#xff0c;没有采购&#xff0c;就没有材料供应&#xff0c;就没有施工生产的顺利进行&#xff0c;因此采购是决定其他三项业务环节的基础因素。 随着流通环节的不断发展壮大&#…

[go学习笔记.第十六章.TCP编程] 1.基本介绍以及入门案例

1.基本介绍 Golang 的主要设计目标之一就是面向大规模后端服务程序&#xff0c;网络通信这块是服务端程序必不可少也是至关重要的一部分. 网络编程有两种户 (1).TCP Socket 编程&#xff0c;是网络编程的主流。之所以叫TCP Socket 编程&#xff0c;是因为底层是基于 TCP/IP 协议…

镍离子去除专业吸附技术,深度除镍工程段工艺设计

含镍废水具有较大的复杂性&#xff0c;难以利用单一的处理方法进行有效处理&#xff0c;现多采用综合处理技术来实现其达标排放及资源的综合利用。 现有的含镍废水处理技术可分为传统化学法、物理法以及电化学法三类。 传统的化学法包括化学沉淀法以及絮凝法等&#xff0c;是通…

因果推理专题讨论01:因果推理概述

因果推理本质属于统计学范畴&#xff0c;并试图从根源上对基于相关性的统计学进行改革。当年诞生统计学科时就发生过分歧&#xff0c;因果被压下去了。直到最近&#xff0c;基于相关性的统计方法几乎发展到尽头&#xff0c;人工智能进一步发展&#xff0c;目前的统计工具已经难…

HTML5期末大作业:仿商城网站设计—— 绿色特产商城购物Html+Css+javascript的网页制作

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…