我们在开发过程中,遇到的最常见的一个异常就是NullPointerException。为了避免空指针异常,平时我们要写很多if判断语句来检查是否为空值。从而导致了大量的if-else嵌套增加了代码的复杂性,降低了代码的可读性和可维护性。
为了解决上面的种种问题Java8引入了一个名为java.util.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 |
- 声明一个空的Optional对象
Optional<Dog> optionalDog = Optional.empty();
- 依据一个非空的值创建一个Optional对象
- 如果dog是一个空值的话这段代码会立即抛出空指针异常,不是等到试图访问optionalDog 的其他方法时才抛出异常。
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.of(dog);
- 创建一个可以接收null的Optional对象
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
从Optional中获取值,如果不存在抛出NoSuchElementException异常
get是这些方法最简答但是又最不安全的一个方法。除非你确定Optional变量一定有值,否则使用这个方法非常不安全。而且这种方式获取值,相对于之前的嵌套时的null检查,也未体现多大的改进。
Dog dog = new Dog("孙富贵", 3);
Optional<Dog> optionalDog = Optional.ofNullable(dog);
System.out.println(optionalDog.get());
- 从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)));
}
运行结果
如果有值就返回,否则返回一个有指定的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);
}
运行结果
- 如果有值则将其返回,没有值时抛出指定的异常
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,"参数为空")));
}
- 如果存在就使用该值调用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=======");
}
- 如果值存在就返回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========");
}
}
- 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)));
}
如下源码
/**
* 如果对象为空返回一个空的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));
}
}
如果值存在并且满足提供的谓词,就返回包含该值的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);
}
假如你有一个需求时从Map
中收集值,当值是正数的时候将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();
}
}