高效处理NPE!!

相信不少小伙伴已经被java的NPE(Null Pointer Exception)所谓的空指针异常搞的头昏脑涨,有大佬说过“防止 NPE,是程序员的基本修养。”但是修养归修养,也是我们程序员最头疼的问题之一,那么我们今天就要尽可能的利用Java8的新特性 Optional来尽量简化代码同时高效处理NPE(Null Pointer Exception 空指针异常)

认识Optional并使用

简单来说,Opitonal类就是Java提供的为了解决大家平时判断对象是否为空用 会用 null!=obj 这样的方式存在的判断,从而令人头疼导致NPE(Null Pointer Exception 空指针异常),同时Optional的存在可以让代码更加简单,可读性跟高,代码写起来更高效.

常规判断:

//对象 人
//属性有 name,age
Person person=new Person();
if (null==person){return person为null;
}
return person;

使用Optional:

//对象 人
//属性有 name,age
Person person=new Person();
return Optional.ofNullable(person).orElse(person为null);

测试展示类Person代码(如果有朋友不明白可以看一下这个):

public class Person {private String name;private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}public Person() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

下面,我们就高效的学习一下神奇的Optional类!

2.1 Optional对象创建

首先我们先打开Optional的内部,去一探究竟 先把几个创建Optional对象的方法提取出来

public final class Optional<T> {private static final Optional<?> EMPTY = new Optional<>();private final T value;//我们可以看到两个构造方格都是private 私有的//说明 我们没办法在外面去new出来Optional对象private Optional() {this.value = null;}private Optional(T value) {this.value = Objects.requireNonNull(value);}//这个静态方法大致 是创建出一个包装值为空的一个对象因为没有任何参数赋值public static<T> Optional<T> empty() {@SuppressWarnings(unchecked)Optional<T> t = (Optional<T>) EMPTY;return t;}//这个静态方法大致 是创建出一个包装值非空的一个对象 因为做了赋值public static <T> Optional<T> of(T value) {return new Optional<>(value);}//这个静态方法大致是 如果参数value为空,则创建空对象,如果不为空,则创建有参对象public static <T> Optional<T> ofNullable(T value) {return value == null ? empty() : of(value);}}

再做一个简单的实例展示 与上面对应

// 1、创建一个包装对象值为空的Optional对象
Optional<String> optEmpty = Optional.empty();
// 2、创建包装对象值非空的Optional对象
Optional<String> optOf = Optional.of(optional);
// 3、创建包装对象值允许为空也可以不为空的Optional对象
Optional<String> optOfNullable1 = Optional.ofNullable(null);
Optional<String> optOfNullable2 = Optional.ofNullable(optional);

我们关于创建Optional对象的内部方法大致分析完毕 接下来也正式的进入Optional的学习与使用中。

2.2 Optional.get()方法(返回对象的值)

get()方法是返回一个option的实例值 源码:

public T get() {if (value == null) {throw new NoSuchElementException(No value present);}return value;
}

也就是如果value不为空则做返回,如果为空则抛出异常 No value present 简单实例展示

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).get();

2.3 Optional.isPresent()方法(判读是否为空)

isPresent()方法就是会返回一个boolean类型值,如果对象不为空则为真,如果为空则false 源码:

public Boolean isPresent() {return value != null;
}

简单的实例展示:

Person person=new Person();
person.setAge(2);
if (Optional.ofNullable(person).isPresent()){//写不为空的逻辑System.out.println(不为空);
} else{//写为空的逻辑System.out.println(为空);
}

2.4 Optional.ifPresent()方法(判读是否为空并返回函数)

这个意思是如果对象非空,则运行函数体 源码:

  public void ifPresent(Consumer<? super T> consumer) {//如果value不为空,则运行accept方法体if (value != null)consumer.accept(value);}

看实例:

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).ifPresent(p -> System.out.println(年龄+p.getAge()));

如果对象不为空,则会打印这个年龄,因为内部已经做了NPE(非空判断),所以就不用担心空指针异常了。

2.5 Optional.filter()方法(过滤对象)

filter()方法大致意思是,接受一个对象,然后对他进行条件过滤,如果条件符合则返回Optional对象本身,如果不符合则返回空Optional

源码:

public Optional<T> filter(Predicate<? super T> predicate) {Objects.requireNonNull(predicate);//如果为空直接返回thisif (!isPresent())return this; else//判断返回本身还是空Optionalreturn predicate.test(value) ? this : empty();
}

简单实例:

Person person=new Person();
person.setAge(2);
Optional.ofNullable(person).filter(p -> p.getAge()>50);

2.6 Optional.map()方法(对象进行二次包装)

map()方法将对应Funcation函数式接口中的对象,进行二次运算,封装成新的对象然后返回在Optional中 源码:

 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {Objects.requireNonNull(mapper);//如果为空返回自己if (!isPresent())return empty();else {//否则返回用方法修饰过的Optionalreturn Optional.ofNullable(mapper.apply(value));}}

实例展示:

Person person1=new Person();
person.setAge(2);
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse(name为空);

2.7 Optional.flatMap()方法(Optional对象进行二次包装)

map()方法将对应Optional< Funcation >函数式接口中的对象,进行二次运算,封装成新的对象然后返回在Optional中 源码:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {Objects.requireNonNull(mapper);if (!isPresent())return empty(); else {return Objects.requireNonNull(mapper.apply(value));}
}

实例:

Person person=new Person();
person.setAge(2);
Optional<Object> optName = Optional.ofNullable(person).map(p -> Optional.ofNullable(p.getName()).orElse(name为空));

2.8 Optional.orElse()方法(为空返回对象)

常用方法之一,这个方法意思是如果包装对象为空的话,就执行orElse方法里的value,如果非空,则返回写入对象 源码:

public T orElse(T other) {//如果非空,返回value,如果为空,返回otherreturn value != null ? value : other;
}

2.9 Optional.orElseGet()方法(为空返回Supplier对象)

这个与orElse很相似,入参不一样,入参为Supplier对象,为空返回传入对象的.get()方法,如果非空则返回当前对象 源码:

public T orElseGet(Supplier<? extends T> other) {return value != null ? value : other.get();
}

实例:

Optional<Supplier<Person>> sup=Optional.ofNullable(Person::new);
//调用get()方法,此时才会调用对象的构造方法,即获得到真正对象
Optional.ofNullable(person).orElseGet(sup.get());

说真的对于Supplier对象我也懵逼了一下,去网上简单查阅才得知 Supplier也是创建对象的一种方式,简单来说,Suppiler是一个接口,是类似Spring的懒加载,声明之后并不会占用内存,只有执行了get()方法之后,才会调用构造方法创建出对象创建对象的语法的话就是Supplier supPerson= Person::new;需要使用时supPerson.get()即可

2.10 Optional.orElseThrow()方法(为空返回异常)

这个我个人在实战中也经常用到这个方法,方法作用的话就是如果为空,就抛出你定义的异常,如果不为空返回当前对象,在实战中所有异常肯定是要处理好的,为了代码的可读性

源码:

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {if (value != null) {return value;} else {throw exceptionSupplier.get();}}

实例:这个就贴实战源码了

//简单的一个查询
Member member = memberService.selectByPhone(request.getPhone());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException(没有查询的相关数据));

2.11 相似方法进行对比分析

可能小伙伴看到这,没用用过的话会觉得orElse()和orElseGet()还有orElseThrow()很相似,map()和flatMap()好相似

哈哈哈不用着急,都是从这一步过来的,我再给大家总结一下不同方法的异同点

orElse()和orElseGet()和orElseThrow()的异同点

方法效果类似,如果对象不为空,则返回对象,如果为空,则返回方法体中的对应参数,所以可以看出这三个方法体中参数是不一样的

  • orElse(T 对象)

  • orElseGet(Supplier < T >对象)

  • orElseThrow(异常)

map()和orElseGet的异同点

  • 方法效果类似,对方法参数进行二次包装,并返回,入参不同

  • map(function函数)

  • flatmap(Optional< function >函数)

具体要怎么用,要根据业务场景以及代码规范来定义,下面可以简单看一下我在实战中怎用使用神奇的Optional

3.实战场景再现

场景1:

在service层中查询一个对象,返回之后判断是否为空并做处理

//查询一个对象
Member member = memberService.selectByIdNo(request.getCertificateNo());
//使用ofNullable加orElseThrow做判断和操作
Optional.ofNullable(member).orElseThrow(() -> new ServiceException(没有查询的相关数据));

场景2:

我们可以在dao接口层中定义返回值时就加上Optional 例如:我使用的是jpa,其他也同理

public interface LocationRepository extends JpaRepository<Location, String> {
Optional<Location> findLocationById(String id);
}

然在是Service中

public TerminalVO findById(String id) {
//这个方法在dao层也是用了Optional包装了Optional<Terminal> terminalOptional = terminalRepository.findById(id);//直接使用isPresent()判断是否为空if (terminalOptional.isPresent()) {//使用get()方法获取对象值Terminal terminal = terminalOptional.get();//在实战中,我们已经免去了用set去赋值的繁琐,直接用BeanCopy去赋值TerminalVO terminalVO = BeanCopyUtils.copyBean(terminal, TerminalVO.class);//调用dao层方法返回包装后的对象Optional<Location> location = locationRepository.findLocationById(terminal.getLocationId());if (location.isPresent()) {terminalVO.setFullName(location.get().getFullName());}return terminalVO;}//不要忘记抛出异常throw new ServiceException(该终端不存在);}

4.Optional使用注意事项

Optional真么好用,真的可以完全替代if判断吗?

我想这肯定是大家使用完之后Optional之后可能会产生的想法,答案是否定的

举一个最简单的栗子:

例子1:

如果我只想判断对象的某一个变量是否为空并且做出判断呢?

Person person=new Person();
person.setName();
persion.setAge(2);
//普通判断
if(StringUtils.isNotBlank(person.getName())){//名称不为空执行代码块
}
//使用Optional做判断
Optional.ofNullable(person).map(p -> p.getName()).orElse(name为空);

我觉得这个例子就能很好的说明这个问题,只是一个很简单判断,如果用了Optional我们还需要考虑包装值,考虑代码书写,考虑方法调用,虽然只有一行,但是可读性并不好,如果别的程序员去读,我觉得肯定没有if看的明显

5.jdk1.9对Optional优化

首先增加了三个方法:

or()、ifPresentOrElse() 和 stream()

or() 与orElse等方法相似,如果对象不为空返回对象,如果为空则返回or()方法中预设的值。

ifPresentOrElse() 方法有两个参数:一个 Consumer 和一个 Runnable。如果对象不为空,会执行 Consumer 的动作,否则运行 Runnable。相比ifPresent()多了OrElse判断。

stream() 将Optional转换成stream,如果有值就返回包含值的stream,如果没值,就返回空的stream。

因为这个jdk1.9的Optional具体我没有测试,同时也发现有蛮好的文章已经也能让大家明白jdk1.9的option的优化,我就不深入去说了。

 ——EOF——


福利:

扫码回复【酒店】可免费领取酒店管理系统源码

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

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

相关文章

Ubuntu22.04安装paddle

查看系统版本信息 使用命令lsb_release -a查看系统版本 rootLAIS01:~# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammy查看系统支持的cuda版本&#xff0c;使用命令nvidia-smi&#…

开源免费的NAS系统-TrueNAS CORE搭建和使用(保姆级教程)

TrueNAS CORE说明 TrueNASCORE(以前称为 FreeNAS)是世界上最受欢迎的存储操作系统,因为它使您能够构建自己的专业级存储系统,用于各种数据密集型应用程序,而无需任何软件成本。只需将其安装到硬件或虚拟机上,即可体验开源存储的真正存储自由。 TrueNAS提供了CORE和Ente…

HTML基础和常用标签

“合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。” 文章目录 前言文章有误敬请斧正 不胜感恩&#xff01;1. HTML的基本结构解释&#xff1a; 2. 常见标签的介绍2.1 标题和文本2.2 链接和图片2.3 列表2.4 …

Dependency Check:一款针对应用程序依赖组件的安全检测工具

关于Dependency Check Dependency-Check 是一款软件组合分析 &#xff08;SCA&#xff09; 工具&#xff0c;可尝试检测项目依赖项中包含的公开披露的漏洞。它通过确定给定依赖项是否存在通用平台枚举 &#xff08;CPE&#xff09; 标识符来实现此目的。如果找到&#xff0c;它…

SSL证书安装、配置和问题定位指南

在运维或者实际的部署、开发&#xff0c;可能涉及到ssl证书相关的问题&#xff0c;尤其前端有些能力&#xff08;摄像头、webrtc&#xff09;等需要在安全的上下文才能使用&#xff0c;cookie的跨iframe生效也需要。关于如何生成和部署证书&#xff0c;很多文字都有介绍&#x…

SaltStack自动化运维部署

一.什么是SaltStack SaltStack是一个服务器基础设施管理工具&#xff0c;它具有配置管理&#xff0c;远程执行&#xff0c;监控等功能&#xff0c;SaltStack由Python语言编写&#xff0c;是非常简单易用和轻量级的管理工具。 二.为什么使用SaltStack 为同时管理多台机器&…

主机和Docker容器之间的文件互传方法汇总

Docker渐渐成为前端的一个工具&#xff0c;它像一个通用包装&#xff0c;可以把各种环境包裹其中&#xff0c;从而实现跨设备的兼容。使用的过程中&#xff0c;往往会需要将本地的文件和docker容器内部的文件互传&#xff1a;将主机的文件传递给容器内&#xff0c;让里面的工具…

向日葵好用吗?4款稳定的远程控制软件推荐。

远程控制技术现在已经被应用于很多个领域&#xff0c;像企业办公&#xff0c;远程协助&#xff0c;智能家居&#xff0c;工业控制等等。我们常常会用到的时前两种。而实现远程控制的方式也有多种&#xff0c;但是最方便高效的还是使用第三方软件。我最常使用的是向日葵&#xf…

城市脉络下的空间句法:中介中心性、接近中心性与绕行率的深度解析

这一篇是对上篇内容的继续深化&#xff0c;也就是sDNA “整体分析”&#xff08;Integral Analysis&#xff09;计算结果代表的意思&#xff0c;有哪些&#xff1f;意义是什么&#xff1f; 上篇文章指路&#xff1a;城市脉络下的空间句法&#xff1a;整合度与选择度的深度解析…

vue实现二维码生成器应用

实现一个简单的二维码生成器应用&#xff0c;可以使用 Vue 前端结合一个 JavaScript 库&#xff08;如 qrcode.js 或 QRCode.js&#xff09;来生成二维码。以下是一个完整的实现步骤&#xff1a; 步骤 1&#xff1a;安装依赖 首先&#xff0c;你需要安装 qrcode 库&#xff0c…

Unity教程(十六)敌人攻击状态的实现

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

macOS平台编译MAVSDK源码生成mavsdk库与mavsdk_server服务可执行文件

克隆源码: 克隆命令 git clone https://github.com/mavlink/MAVSDK.git --recursive 克隆成功如下: 生成makefile (只生成mavsdk库) cmake -Bbuild/default -DCMAKE_BUILD_TYPE=Debug -H. 指定安装目录与生成目录: cmake -Bbuild/macos -DCMAKE_BUILD_TYPE=Debug -…

pg入门3—详解tablespaces2

pg默认的tablespace的location为空&#xff0c;那么如果表设置了默认的tablespace&#xff0c;数据实际上是存哪个目录的呢? 在 PostgreSQL 中&#xff0c;如果你创建了一个表并且没有显式指定表空间&#xff08;tablespace&#xff09;&#xff0c;或者表空间的 location 为…

面试官问:你如何处理与同事或上级的分歧?【无标题】

面试官问&#xff1a;你如何处理与同事或上级的分歧&#xff1f; 当面试官问你如何处理与同事或上级的分歧&#xff0c;其实面试官的目的是评估你的沟通技巧、冲突解决能力和团队合作的能力。在一起共事&#xff0c;就一定有分歧发生&#xff0c;有争执是正常的&#xff0c;关…

OJ在线评测系统 思考主流OJ的实现方案 常用概念 自己的思考

OJ判题系统常用概念 OJ系统 在线判题系统 AC all accpeted 测试样例全部通过 题目介绍 题目输入 题目输出 题目输出用例 题目输入用例 不能让用户随便引入包 随便遍历 暴力破解 需要使用正确的算法 提交后不会立刻出结果 而是异步处理 提交后会生成一个提交记录 有运…

大牛直播SDK核心音视频模块探究

技术背景 视沃科技旗下”大牛直播SDK”&#xff0c;始于2015年&#xff0c;致力于传统行业极致体验的音视频直播技术解决方案&#xff0c;产品涵盖跨平台的实时RTMP推流、RTMP/RTSP直播播放(支持RTSP|RTMP H.265&#xff0c;Enhanced RTMP H.265)、GB28181设备接入、推送端播放…

内存管理篇-27寄存器映射:ioremap

驱动在读写寄存器是&#xff0c;需要将寄存器进行ioremap。在x86上&#xff0c;通过专用的指令进行编址访问&#xff0c;但是在arm上是进行统一的编址&#xff08;占用32位4GB空间的某一小段&#xff09;&#xff0c;因此也叫memory-map的设备。 实现机制&#xff1a;

【IPOL阅读】点云双边滤波

文章目录 简介点云滤波处理结果 简介 IPOL&#xff0c;即Image Processing On Line&#xff0c;理论上是一个期刊&#xff0c;但影响因子很低&#xff0c;只是个SCIE&#xff0c;按理说没什么参考价值。但是&#xff0c;这个网站的所有文章&#xff0c;都附带了源代码和演示窗…

阿里云CTO:通义稳居全球最强开源大模型,性能接近GPT-4o

来源&#xff1a;首席数智官 9月19日&#xff0c;在2024杭州云栖大会上&#xff0c;阿里云CTO周靖人表示&#xff0c;阿里云正在围绕AI时代&#xff0c;树立一个AI基础设施的新标准&#xff0c;全面升级从服务器到计算、存储、网络、数据处理、模型训练和推理平台的技术架构体…

python+flask+mongodb+vue撸一个实时监控linux服务资源的网站

用pythonflaskmongodbvue写一个监控linux服务资源实时使用率的页面网站&#xff0c;并每30秒定时请求&#xff0c;把Linux数据保存数据到mongodb数据库中&#xff0c;监控的linux的资源有&#xff1a;cup、内存、网络带宽、mysql慢查询、redis、系统平均负载、磁盘使用率等&…