持续创作,加速成长!这是我参与「掘金日新计划 · 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
- 声明一个 Girl 类型,包含姓名(String)属性
- 声明一个 Boy 类型,包含姓名(String),女朋友(Girl)属性
- 在测试类中,创建一个 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
-
声明学生类,包含姓名和年龄
-
添加几个学生对象到一个 ArrayList 集合中
-
对集合中的学生进行操作,找出年龄大于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());
}
复制代码