`「胜利案例」正确的倍投6种办法陈北叩【753~7227——码:9588~9990】
Java Optional使用指南
2021-01-29 09:46 申城异乡人 浏览(146) 评论(1) 编辑 珍藏)
提到NullPointerException(简称NPE)异样,置信每个Java开发人员都不生疏,从接触编程的第1天起,它就和咱们如影随形,最近解决的线上bug中,有不少都是对象没判空导致的NullPointerException异样。
- 简略回顾
引起NullPointerException异样的中央有很多,比方调用String的trim()办法,比方对BigDecimal进行计算时,比方将包装类型转化为根本类型时,这里简略回顾下。
假如有个导入模版定义如下:
``java
package com.zwwhnly.springbootaction.model;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
- 导入模版
*/
@Data
@AllArgsConstructor
public class ImportTemplate {
/** * 模版id */private int templateId;/** * 模版名称 */private String templateName;/** * 模版下载url */private String url;/** * 备注 */private String remark;
}
`
而后看下如下代码:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);System.out.println(importTemplate.getUrl());
}
public static ImportTemplate getImportTemplateById(int id) {
return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
失常状况下,这段代码必定是没有问题的,但当getImportTemplateById办法返回null时,这段代码就会抛出NullPointerException异样,如下所示:
`
public static ImportTemplate getImportTemplateById(int id) {
return null;
}
`
为了程序能失常运行,就要判断importTemplate是否为null,所以代码就批改为了:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);if (importTemplate != null) { System.out.println(importTemplate.getUrl());}
}
`
我的项目中相似的判空代码应该有很多,大家能够自行看下本人我的项目的代码。
- 应用Optional
为了防止NullPointerException异样,JDK1.8新增了Optional类来解决空指针异样,该类位于java.util包下,提供了一系列办法,
并且能够配合Lambda表达式一起应用,使代码看起来更加清晰,接下来咱们看下它的应用办法。
2.1 创立实例
创立Optional实例有以下3种形式,别离为:
- 调用empty办法
`java
Optional<ImportTemplate> optionalImportTemplate = Optional.empty();
` 调用of办法
`java
ImportTemplate importTemplate = new ImportTemplate(1, "销售订单-普通商品导入模版","o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.of(importTemplate);
`调用ofNullable办法(举荐)
`java
ImportTemplate importTemplate = new ImportTemplate(1, "销售订单-普通商品导入模版","o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
`
值得注意的是,当参数为null时,调用of办法会抛NullPointerException异样,但调用ofNullable办法不会(更合乎应用场景),因而举荐应用ofNullable办法:
`java
ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.of(importTemplate);
`
2.2 判断是否有值
能够调用isPresent办法来判断对象是否有值(不为null),应用办法如下所示:
`java
ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.isPresent());
`
以上代码的输入后果为:
`java
ImportTemplate importTemplate = new ImportTemplate(1, "销售订单-普通商品导入模版",
"o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.isPresent());
`
以上代码的输入后果为:
看下isPresent的源码,逻辑非常简单,就是判断了咱们传入的对象是否有值,即不为null:
`java
/**
- Return {@code true} if there is a value present, otherwise {@code false}.
*
- @return {@code true} if there is a value present, otherwise {@code false}
*/
public boolean isPresent() {
return value != null;
}
`
2.3 获取值
能够调用get办法来获取对象的有值,应用办法如下所示:
`java
ImportTemplate importTemplate = new ImportTemplate(1, "销售订单-普通商品导入模版",
"o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.get());
`
以上代码的输入后果为:
值得注意的是,当咱们传入的对象为null时,调用get办法会抛出java.util.NoSuchElementException异样,而不是返回null。
`java
ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.get());
`
以上代码的输入后果为:
看下get办法的源码,就能够晓得起因:
`java
public T get() {
if (value == null) { throw new NoSuchElementException("No value present");}return value;
}
`
2.4 先用isPresent,再用get(不举荐)
而后咱们回顾下文初的代码:
`java
ImportTemplate importTemplate = getImportTemplateById(1);
if (importTemplate != null) {
System.out.println(importTemplate.getUrl());
}
`
可能很多同学会把代码优化为上面这样的写法:
`java
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
if (optionalImportTemplate.isPresent()) {
System.out.println(optionalImportTemplate.get().getUrl());
}
`
不举荐这么应用,因为判断的中央没缩小,而且还不如原来看起来清晰。
2.5 ifPresent(举荐)
那该怎么优化呢?答案就是应用ifPresent办法,该办法接管一个Consumer类型的参数,当值不为null时,就执行,当值为null时,就不执行,源码如下所示:
`java
public void ifPresent(Consumer<? super T> consumer) {
if (value != null) consumer.accept(value);
}
`
优化之后的代码如下所示:
`java
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
optionalImportTemplate.ifPresent(importTemplate -> System.out.println(importTemplate.getUrl()));
`
当然,也能够写更多的逻辑:
`java
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
optionalImportTemplate.ifPresent(importTemplate -> {
System.out.println(importTemplate.getTemplateId());System.out.println(importTemplate.getTemplateName());System.out.println(importTemplate.getUrl());System.out.println(importTemplate.getRemark());
});
`
2.6 自定义默认值
Optional类提供了以下2个办法来自定义默认值,用于当对象为null时,返回自定义的对象:
- orElse
- orElseGet
先来看下orElse办法的应用:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = null;ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate) .orElse(getDefaultTemplate());System.out.println(firstImportTemplate);importTemplate = new ImportTemplate(2, "销售订单-不定规格商品导入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate) .orElse(getDefaultTemplate());System.out.println(secondImportTemplate);
}
public static ImportTemplate getDefaultTemplate() {
System.out.println("getDefaultTemplate");return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
输入后果:
再来看下orElseGet办法的应用:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = null;ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate) .orElseGet(() -> getDefaultTemplate());System.out.println(firstImportTemplate);importTemplate = new ImportTemplate(2, "销售订单-不定规格商品导入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate) .orElseGet(() -> getDefaultTemplate());System.out.println(secondImportTemplate);
}
public static ImportTemplate getDefaultTemplate() {
System.out.println("getDefaultTemplate");return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
输入后果:
从输入后果看,2个办法如同差不多,第1次调用都返回了默认模版,第2次调用都返回了传入的模版,但其实仔细观察,你会发现当应用
orElse办法时,getDefaultTemplate办法执行了2次,但调用orElseGet办法时,getDefaultTemplate办法只执行了2次(只在第1次传入模版为null时执行了)。
为什么会这样呢?带着这个疑难,咱们看下这2个办法的源码,其中orElse办法的源码如下所示:
`java
public T orElse(T other) {
return value != null ? value : other;
}
`
能够看到,参数other是个对象,这个参数必定是要传的,但只有value为空时,才会用到(返回)这个对象。
orElseGet办法的源码如下所示:
`java
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
`
能够看到,参数other并不是间接传入对象,如果value为null,才会执行传入的参数获取对象,如果不为null,间接返回value。
2.7 自定义异样
Optional类提供了orElseThrow办法,用于当传入的对象为null时,抛出自定义的异样,应用办法如下所示:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = new ImportTemplate(2, "销售订单-不定规格商品导入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate) .orElseThrow(() -> new IndexOutOfBoundsException());System.out.println(firstImportTemplate);importTemplate = null;ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate) .orElseThrow(() -> new IndexOutOfBoundsException());System.out.println(secondImportTemplate);
}
`
输入后果:
2.8 过滤数据
Optional类提供了filter办法来过滤数据,该办法接管一个Predicate参数,返回匹配条件的数据,如果不匹配条件,返回一个空的Optional,应用办法如下所示:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);Optional<ImportTemplate> filterById = Optional.ofNullable(importTemplate) .filter(f -> f.getTemplateId() == 1);System.out.println(filterById.isPresent());Optional<ImportTemplate> filterByName = Optional.ofNullable(importTemplate) .filter(f -> f.getTemplateName().contains("发货单"));System.out.println(filterByName.isPresent());
}
public static ImportTemplate getImportTemplateById(int id) {
return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
输入后果:
2.9 转换值
Optional类提供了以下2个办法来转换值:
- map
- flatMap
map办法的应用办法如下所示:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);Optional<String> optionalUrl = Optional.ofNullable(importTemplate) .map(f -> "url:" + f.getUrl());System.out.println(optionalUrl.isPresent());System.out.println(optionalUrl.get());
}
public static ImportTemplate getImportTemplateById(int id) {
return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
输入后果:
flatMap办法和map办法相似,不过它反对传入Optional,应用办法如下所示:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);Optional<String> optionalUrl = Optional.ofNullable(importTemplate) .flatMap(f -> Optional.ofNullable(f.getUrl()));System.out.println(optionalUrl.isPresent());System.out.println(optionalUrl.get());
}
public static ImportTemplate getImportTemplateById(int id) {
return new ImportTemplate(1, "销售订单-普通商品导入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}
`
输入后果:
- 总结
对于程序员来说,一不注意就会呈现NullPointerException异样,防止它的形式也很简略,比方应用前判断不能为空:
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);if (importTemplate != null) { System.out.println(importTemplate.getUrl());}
}
`
比方为空时,间接返回(或者返回默认值):
`java
public static void main(String[] args) {
ImportTemplate importTemplate = getImportTemplateById(1);if (importTemplate == null) { return;}System.out.println(importTemplate.getUrl());
}
`
比方,应用本文中的Optional。
应用哪种形式不重要,尽可能地防止NullPointerException`异样才重要。
- 参考
了解、学习与应用 Java 中的 Optional`