Java - Optional 类

57 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

背景

到目前为止,臭名昭著的空指针异常是导致 Java 应用程序失败的最常见原因

以前,为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional 类已经成为 Java 8 类库的一部分。

简介

  • Optional 实际上是个容器:它可以保存类型 T 的值,或者仅仅保存 null

  • Optional 提供很多有用的方法,这样我们就不用显式进行空值检测

API

如何创建 Optional 对象?或者说如何用 Optional 来装值对象或 null 值

  • static  Optional empty() :用来创建一个空的 Optional

  • static  Optional of(T value):用来创建一个非空的 Optional

  • static  Optional ofNullable(T value):用来创建一个可能是空,也可能非空的 Optional

如何从 Optional 容器中取出所包装的对象呢?

T get()

  • 要求 Optional 容器必须非空
  • T get()of(T value)使用是安全的

T orElse(T other)

  • ofNullable(T value)配合使用

  • 如果 Optional 容器中非空,就返回包装值,如果为空,就用 other 指定的默认值(备胎)代替

T orElseGet(Supplier<? extends T> other)

如果 Optional 容器中非空,就返回包装值,如果为空,就用 Supplier 接口的 Lambda 表达式提供的值代替

T orElseThrow(Supplier<? extends X> exceptionSupplier)

如果 Optional 容器中非空,就返回所包装值,如果为空,就抛出指定的异常类型代替原来的 NoSuchElementException

其他方法

  • boolean isPresent():判断 Optional 容器中的值是否存在
  • void ifPresent(Consumer<? super T> consumer):判断 Optional 容器中的值是否存在,如果存在,就对它进行 Consumer 指定的操作,如果不存在就不做
  • Optional map(Function<? super T,? extends U> mapper):判断 Optional 容器中的值是否存在,如果存在,就对它进行 Function 接口指定的操作,如果不存在就不做
  • Optional<T> filter(Predicate<? super T> predicate):过滤 Optional 容器中的值,如果不存在返回空,如果存在则进行判断,不符合条件则返回 null,符合条件则返回自己本身
package com.atguigu.test07;

import java.util.ArrayList;
import java.util.Optional;

import org.junit.Test;

public class TestOptional {
	@Test
	public void test9(){
		String str = "Hello";
		Optional<String> opt = Optional.ofNullable(str);
        //判断是否是纯字母单词,如果是,转为大写,否则保持不变
		String result = opt.filter(s->s.matches("[a-zA-Z]+")).
				map(s -> s.toLowerCase()).
				orElse(str);
		System.out.println(result);
	}
	
	
	@Test
	public void test8(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElseThrow(()->new RuntimeException("值不存在"));
		System.out.println(string);
	}
	
	
	@Test
	public void test7(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElseGet(String::new);
		System.out.println(string);
	}
	
	@Test
	public void test6(){
		String str = "hello";
		Optional<String> opt = Optional.ofNullable(str);
		String string = opt.orElse("polo");
		System.out.println(string);
	}
	
	@Test
	public void test5(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
//		System.out.println(opt.get());//java.util.NoSuchElementException: No value present
	}
	
	@Test
	public void test4(){
		String str = "hello";
		Optional<String> opt = Optional.of(str);

		String string = opt.get();
		System.out.println(string);
	}
	
	
	@Test
	public void test3(){
		String str = null;
		Optional<String> opt = Optional.ofNullable(str);
		System.out.println(opt);
	}
	
	@Test
	public void test2(){
		String str = "hello";
		Optional<String> opt = Optional.of(str);
		System.out.println(opt);
	}

}

练习

练习1

  1. 声明一个 Girl 类型,包含姓名(String)属性
  2. 声明一个 Boy 类型,包含姓名(String),女朋友(Girl)属性
  3. 在测试类中,创建一个 Boy 对象,如果他有女朋友,显示他女朋友名称;如果他没有女朋友,他的女朋友默认为“嫦娥”
class Girl{
	private String name;

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Girl [name=" + name + "]";
	}
	
}
class Boy{
	private String name;
	private Girl girlFriend;
	public Boy(String name, Girl girlFriend) {
		super();
		this.name = name;
		this.girlFriend = girlFriend;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Girl getGirlFriend() {
		return girlFriend;
	}
	public void setGirlFriend(Girl girlFriend) {
		this.girlFriend = girlFriend;
	}
	@Override
	public String toString() {
		return "Boy [name=" + name + ", girlFriend=" + girlFriend + "]";
	}
	
}

测试类

	public static void main(String[] args) {
//		Boy boy = new Boy("张三",null);
		Boy boy = new Boy("张三",new Girl("翠翠"));
		Optional<Girl> grilFriend = Optional.ofNullable(boy.getGirlFriend());
		Optional.of(grilFriend.orElse(new Girl("嫦娥"))).ifPresent(g->System.out.println(g));
	}

练习2

  1. 声明学生类,包含姓名和年龄

  2. 添加几个学生对象到一个 ArrayList 集合中

  3. 对集合中的学生进行操作,找出年龄大于30岁的,并取出第一个学生,如果没有这样的学生,用无参构造 new 一个学生对象,打印学生信息

学生类

class Student{
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {
		super();
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}

测试类

	
	@Test
	public void test1(){
		ArrayList<Student> list = new ArrayList<>();
		list.add(new Student("张三", 23));
		//...
		
		//取出流中第一个年龄大于30岁的学生的年龄,并打印它的年龄,如果没有,用无参构造创建一个学生对象
		Student stu = list.stream()
			.filter(s -> s.getAge()>30)
			.findFirst().orElse(new Student());
		System.out.println("学生的年龄:" + stu.getAge());
	}