文章目录
一、前言
我们在开发过程中,遇到的最常见的一个异常就是NullPointerException。为了避免空指针异常,平时我们要写很多if判断语句来检查是否为空值。从而导致了大量的if-else嵌套增加了代码的复杂性,降低了代码的可读性和可维护性。
1.1 null的原罪
- 它是错误之源
空指针异常,是目前java程序开发中最经典的异常。 - 它会使你的代码膨胀
他会让你的代码充斥着深度的null检查,代码的可读性糟糕透顶。 - 它自身是毫无意义的
null自身没有任何语义,尤其是它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。 - 它破坏了Java的哲学
Java是一直试图避免让程序员意识到指针的存在,唯一的例外就是:null指针 - 它是Java类型系统上开了个口子
null并不属于任何类型,这意味着他可以被赋值给任何引用类型的变量。这会存在一个问题,当这个变量被传递给系统的另一部分时,你将无法获知这个null最初被赋值给什么类型。
1.2 Optional类诞生
为了解决上面的种种问题Java8引入了一个名为java.util.Optional的新类。他表示一个可能有值也可能没有值的对象。它提供了一系列的方法,方便我们来构建我们的代码。
二、Optional类介绍
2.1 Optional类的方法
方法 | 描述 |
---|---|
empty | 返回一个空的Optional实例 |
of | 将指定的值用Optional封装之后返回,如果该值为null,则抛出一个NullPointerException异常 |
ofNullable | 将指定的值用Optional封装后返回,如果该值为null,则封装一个空的Optional对象 |
get | 如果存在就将Optional封装的的值返回,否则抛出一个NoSuchElementException |
orElse | 如果有值则将其值返回,否则返回一个默认值 |
orElseGet | 如果有值就返回,否则返回一个有指定的Supplier生成的值 |
orElseThrow | 如果有值则将其返回,没有值时抛出指定的异常 |
ifPresent | 如果存在就使用该值调用consumer,否则什么也不做 |
filter | 如果值存在并且满足提供的谓词,就返回包含该值的Optional对象。否则返回一个空的Optional对象 |
map | 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional |
flatMap | 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional |
isPresent | 如果值存在就返回true,否则返回false |
2.2 方法详解
2.2.1 创建Optional对象
1)empty
- 声明一个空的Optional对象
Optional<Dog> optionalDog = Optional.empty();
2)of
- 依据一个非空的值创建一个Optional对象
- 如果dog是一个空值的话这段代码会立即抛出空指针异常,不是等到试图访问optionalDog 的其他方法时才抛出异常。
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.of(dog);
3)ofNullable
- 创建一个可以接收null的Optional对象
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
2.2.2 从Optional中获取值
1)get
从Optional中获取值,如果不存在抛出NoSuchElementException异常
get是这些方法最简答但是又最不安全的一个方法。除非你确定Optional变量一定有值,否则使用这个方法非常不安全。而且这种方式获取值,相对于之前的嵌套时的null检查,也未体现多大的改进。
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
System.out.println(optionalDog.get());
2)orElse
- 从Optional对象获取值,不存在时返回默认值
public static void main(String[] args) {
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
System.out.println(optionalDog.orElse(new Dog("假孙富贵", 12)));
System.out.println("==============");
Dog dog2 = null;
Optional<Dog> optionalDog2 = Optional.ofNullable(dog2);
System.out.println(optionalDog2.orElse(new Dog("假孙富贵", 12)));
}
运行结果
3)orElseGet
如果有值就返回,否则返回一个有指定的Supplier生成的值
public static void main(String[] args) {
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
System.out.println(optionalDog.orElseGet(()->getDefaultDog()));
System.out.println("==============");
Dog dog2 = null;
Optional<Dog> optionalDog2 = Optional.ofNullable(dog2);
System.out.println(optionalDog2.orElseGet(()->getDefaultDog()));
}
private static Dog getDefaultDog(){
return new Dog("假孙富贵", 12);
}
运行结果
4)orElseThrow
- 如果有值则将其返回,没有值时抛出指定的异常
public static void main(String[] args) {
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
System.out.println(optionalDog.orElseThrow(() -> new ParamException(400,"参数为空")));
System.out.println("==============");
Dog dog2 = null;
Optional<Dog> optionalDog2 = Optional.ofNullable(dog2);
System.out.println(optionalDog2.orElseThrow(() -> new ParamException(400,"参数为空")));
}
运行结果
5) ifPresent
- 如果存在就使用该值调用consumer,否则什么也不做
public static void main(String[] args) {
System.out.println("=======BEGIN=======");
Optional.ofNullable(new Dog("孙富贵", 3)).ifPresent(System.out::println);
System.out.println("===================");
Optional.ofNullable(null).ifPresent(System.out::println);
System.out.println("=========END=======");
}
运行结果
2.2.3 其他方法
1) isPresent
- 如果值存在就返回true,否则返回false
public static void main(String[] args) {
printDog(Optional.ofNullable(new Dog("孙富贵", 3)));
printDog(Optional.ofNullable(null));
}
private static void printDog(Optional<Dog> optionalDog) {
if (optionalDog.isPresent()) {
System.out.println(optionalDog.get());
} else {
System.out.println("======NULL========");
}
}
运行结果
2)map和flatMap
- map如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional
- flatMap如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的
public static void main(String[] args) {
System.out.println(getDogName(Optional.ofNullable(new Dog("孙富贵", 3))));
System.out.println(getDogName(Optional.ofNullable(null)));
}
private static String getDogName (Optional<Dog> optionalDog) {
return optionalDog.map(Dog::getName).orElse("UNCHECK");
}
运行结果
public static void main(String[] args) {
List<Optional<Dog>> list = Arrays.asList(Optional.ofNullable(new Dog("孙富贵", 3)));
System.out.println(Optional.ofNullable(list).map(a -> a.get(0)));
System.out.println(Optional.ofNullable(list).flatMap(a -> a.get(0)));
}
运行结果
注意
- map和flatMap容易弄混淆都是通过传入一个function返回一个Optional对象。但是这两个是有区别的
- map会把function执行之后的结果转成Optional对象返回不管结果是什么类型。
- flatMap传入的function执行结果必须是一个Optional对象,flatMap会直接把这个对象返回。
如下源码
/**
* 如果对象为空返回一个空的Optional对象
* 会将mapper执行后的结果转换成Optional对象返回
*/
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
/**
* 如果对象为空返回一个空的Optional对象
* 会将mapper执行后的结果直接返回,但是mapper是有条件的返回的结果是个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));
}
}
3)filter
如果值存在并且满足提供的谓词,就返回包含该值的Optional对象。否则返回一个空的Optional对象
public static void main(String[] args) {
Optional<Dog> optionalDog = Optional.ofNullable(new Dog("孙富贵", 3)).filter(a -> a.getName() != null && a.getName().contains("富贵"));
System.out.println(optionalDog);
Optional<Dog> optionalDog2 = Optional.ofNullable(new Dog("孙富贵", 3)).filter(a -> a.getName() != null && a.getName().contains("钱"));
System.out.println(optionalDog2);
}
运行结果
三、使用实例
3.1 综合使用
假如你有一个需求时从Map<String,String>中收集值,当值是正数的时候将String转成正数收集当值是负数或者其他的类型时存0。
老的实现方法
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.put("c", "c");
map.put("d", "-1");
List<Integer> list = new ArrayList<>();
map.forEach((k, v) -> list.add(readDuration(map, k)));
list.forEach(System.out::println);
}
private static Integer readDuration(Map<String, String> map, String name) {
String value = map.get(name);
if (value != null) {
try {
int i = Integer.parseInt(value);
if (i > 0) {
return i;
}
} catch (NumberFormatException e) {
return 0;
}
}
return 0;
}
用Optional的实现方法
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.put("c", "c");
map.put("d", "-1");
List<Integer> list = new ArrayList<>();
map.forEach((k, v) -> list.add(readDuration(map, k)));
list.forEach(System.out::println);
}
private static Integer readDuration(Map<String, String> map, String name) {
return Optional.ofNullable(map.get(name))
.flatMap(OptionalDemo::stringToInt)
.filter(b -> b > 0)
.orElse(0);
}
private static Optional<Integer> stringToInt(String s) {
try {
return Optional.ofNullable(s).map(Integer::parseInt);
} catch (Exception e) {
return Optional.empty();
}
}