使用Optional取代null
  TEZNKK3IfmPf 2023年11月12日 20 0

在Java中对一个空对象进行操作时,便会抛出最常见的异常​​NullPointerException​​​。为了改善这个问题,Java 8中提供了一个​​java.util.Optional<T>​​​类型。Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则​​isPresent()​​​方法会返回true,调用​​get()​​方法会返回该对象。下面介绍Optional类的使用方法。假如有一个像下面这样的类层次结构:

class Department {
private Employee employee;

public Department(Employee employee) {
this.employee = employee;
}

Employee getEmployee() {
return employee;
}
}

class Employee {
private Girl girlFriend;

public Employee(Girl girlFriend) {
this.girlFriend = girlFriend;
}

Girl getGirlFriend() {
return girlFriend;
}
}

class Girl {
private String name;

public Girl(String name) {
this.name = name;
}

String getName() {
return name;
}
}

部门​​Department​​​类包含一个员工​​employee​​​属性,类型为​​Employee​​​,员工​​Employee​​​类包含​​girlFriend​​​属性,类型为​​Girl​​。假如现在要获取部门某个员工的女朋友,我们通常是这样获取的:

static String getGirlFriendName(Department department) {
if (department != null) {
Employee employee = department.getEmployee();
if (employee != null) {
Girl girl = employee.getGirlFriend();
if (girl != null) {
return girl.getName();
}
return "单身汪";
}
return "没有员工";
}
return "部门为空";
}

可以看到,在每次引用变量的属性时,都要先判断变量是否为空,如果不做该检查将可能导致​​NullPointerException​​。下面我们将使用Optional来改善这种层层嵌套,啰嗦的代码。

创建一个Optional对象有好几种方式:

创建一个空的Optional

我们可以使用静态工厂方法​​Optional.empty​​,创建一个空的Optional对象:

Optional<Department> department = Optional.empty();

根据非空值创建Optional

我们也可以使用静态工厂方法​​Optional.of​​来创建一个非空对象的Optional对象,也就是不能为空:

public static void main(String[] args) {
Employee employee = new Employee(new Girl("翠花"));
Optional<Employee> optEmployee = Optional.of(employee);
}

如果employee为空,这段代码会立即抛出一个​​NullPointerException​​。

创建可以为null的Optional

使用静态工厂方法​​Optional.ofNullable​​,我们可以创建一个允许null值的Optional对象:

public static void main(String[] args) {
Employee employee = new Employee(new Girl("翠花"));
Optional<Employee> optEmployee = Optional.ofNullable(employee);
}

如果employee为空,对其调用​​get​​​方法将抛出​​NoSuchElementException​​。

Optional方法

Optional类包含了许多方法,下面介绍这些方法的使用。

isPresent

顾名思义,如果值存在返回true,否则返回false。如:

public static void main(String[] args) {
Department department = new Department(new Employee(new Girl("翠花")));
Optional<Department> opt = Optional.ofNullable(department);
if (opt.isPresent()) {
System.out.println(opt.get().getEmployee());
}
}

get

如果Optional有值则将其返回,否则抛出​​NoSuchElementException​​​。下面举个抛出​​NoSuchElementException​​的例子:

public static void main(String[] args) {
try {
Optional.empty().get();
} catch (Exception e) {
e.printStackTrace();
}
}

代码将捕获到 ​​java.util.NoSuchElementException: No value present​​ 异常。

ifPresent

如果Optional实例有值则为其调用​​Consumer​​​(函数描述符为​​T -> void​​)否则不做处理。如:

public static void main(String[] args) {
Optional<Girl> girl = Optional.of(new Girl("想想"));
girl.ifPresent(g -> System.out.println("我有女朋友,名字是:" + g.getName()));
}

orElse

如果Optional实例有值则将其返回,否则返回​​orElse​​方法传入的参数。如:

public static void main(String[] args) {
System.out.println(Optional.empty().orElse("There is no value present!"));
}

程序将输出​​There is no value present!​​。

orElseGet

​orElseGet​​​与​​orElse​​​方法类似,​​orElse​​​方法将传入的字符串作为默认值,而​​orElseGet​​​方法可以接受​​Supplier​​​(函数描述符为​​() -> T​​)来生成默认值。如:

public static void main(String[] args) {
System.out.println(Optional.empty().orElseGet(() -> "There is no value present!"));
}

程序同样输出​​There is no value present!​​。

orElseThrow

如果有值则将其返回,否则抛出​​Supplier​​接口创建的异常。如:

public static void main(String[] args) {
try {
Optional.empty().orElseThrow(NoSuchElementException::new);
} catch (Exception e) {
e.printStackTrace();
}
}

代码将捕获到 ​​java.util.NoSuchElementException: No value present​​ 异常。

map

如果Optional有值,则对其执行调用​​Function​​​函数描述符为(​​T -> R​​​)得到返回值。如果返回值不为null,则创建包含​​Function​​绘制的Optional作为map方法的返回值,否则返回一个空Optional。

public static void main(String[] args) {
Optional<String> name = Optional.of("scott");
Optional<String> upperName = name.map(String::toUpperCase);
System.out.println(upperName.orElse("No value found"));
}

flatMap

如果有值,为其执行​​Function​​​函数返回Optional类型返回值,否则返回空Optional。​​flatMap​​​与​​map​​​方法类似,区别在于​​flatMap​​​中的​​Function​​​函数返回值必须是Optional。调用结束时,​​flatMap​​不会对结果用Optional封装。如:

public static void main(String[] args) {
Optional<String> name = Optional.of("Jane");
Optional<String> upperName = name.filter((value) -> value.length() >= 3);
upperName = name.flatMap((value) -> Optional.of(value.toUpperCase()));
System.out.println(upperName.orElse("No value found"));
}

filter

filter方法通过传入​​Predicate​​​(函数描述符为​​T -> Boolean​​)对Optional实例的值进行过滤。如:

public static void main(String[] args) {
Optional<String> name = Optional.of("Jane");
Optional<String> LongName = name.filter((value) -> value.length() >= 3);
System.out.println(LongName.orElse("名字长度小于3个字符"));
}

方法输出​​Jane​​。

使用Optional取代null

实战

介绍完Optional类的方法后,我们使用Optional改善一开始的代码:

public static void main(String[] args) {
Department department = new Department(new Employee(new Girl("翠花")));
System.out.println(getGirlFriendName(department));
}

static String getGirlFriendName(Department department) {
Optional<Department> opt = Optional.ofNullable(department);
return opt.map(Department::getEmployee)
.map(Employee::getGirlFriend)
.map(Girl::getName)
.orElseThrow(NoSuchElementException::new);
}
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: TypeScript-类 下一篇: TypeScript-泛型约束
  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

TEZNKK3IfmPf