背景
Optional是一個容器,用來管理一個對象。主要是用來解決null和NullPointerException問題。
Java7 -> Java8 Optional是如何簡化你的代碼
假設有一個Student類
@Data
public class Student {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
}
舉例一
//java7
private String getJava7UpperCaseStudentName(Student student) {
if (student != null) {
String name = student.getName();
if (name != null) {
return name.toUpperCase();
}
}
return null;
}
//java8
private String getJava8UpperCaseStudentName(Student student) {
return Optional.ofNullable(student).map(Student::getName).map(String::toUpperCase).orElse(null);
}
舉例二
@Test
public void testOptionalOrElse() {
Student origin = null;
Student defaultStudent = new Student("default", -1);
//java7
Student java7Student = origin != null ? origin : defaultStudent;
//java8
Student java8Student = Optional.ofNullable(origin).orElse(defaultStudent);
System.out.println("java7Student : " + java7Student);
System.out.println("java8Student : " + java8Student);
}
可見,使用Optional可以簡化代碼。
用法及測試
of()、ofNullable()和empty()
@Test
public void testEmptyOptional() {
Optional<Student> emptyOptional = Optional.empty();
System.out.println("emptyOptional.isPresent:" + emptyOptional.isPresent());
}
@Test
public void testOptional() {
Optional<Student> nullStudentOptional = Optional.ofNullable(null);
Optional<Student> studentOptional = Optional.of(new Student("a", 1));
System.out.println("nullStudentOptional:" + nullStudentOptional.orElse(null));
System.out.println("studentOptional:" + studentOptional.orElse(null));
}
輸出結果
emptyOptional.isPresent:false
nullStudentOptional:null
studentOptional:Student(name=a, age=1)
of()函數傳入的Object不能爲空,否則會直接拋出空指針異常
ofNullable()函數傳入的Object可爲空
empty()函數會創建一個空的Optional對象,其value爲null
isPresent()
@Test
public void testOptionalIsPresent() {
Optional<Student> nullStudentOptional = Optional.ofNullable(null);
Optional<Student> studentOptional = Optional.of(new Student("a", 1));
System.out.println("nullStudentOptional.isPresent():" + nullStudentOptional.isPresent());
System.out.println("studentOptional.isPresent():" + studentOptional.isPresent());
}
輸出結果
nullStudentOptional.isPresent():false
studentOptional.isPresent():true
isPresent()函數會判斷當前Optional容器保存的對象是否不爲空,true表示不爲空,false表示爲空
IfPresent()
@Test
public void testOptionalIfPresent() {
Optional<Student> studentOptional1 = Optional.of(new Student("a", 1));
studentOptional1.ifPresent(student -> {
System.out.println("accept student:" + student);
student.setAge(student.getAge() * 2);
student.setName(student.getName() + "-accept");
});
System.out.println("after accept student:" + studentOptional1.orElse(null));
}
運行結果
accept student:Student(name=a, age=1)
after accept student:Student(name=a-accept, age=2)
orElseThrow()、orElseGet()
@Test
public void testOptionalOrElseThrow() {
Optional<Student> studentOptional = Optional.ofNullable(null);
Student student = studentOptional.orElseThrow(() -> new NullPointerException("studentOptional is null"));
System.out.println("student : " + student);
}
@Test
public void testOptionalOrElseGet() {
Optional<Student> studentOptional = Optional.ofNullable(null);
Student student = studentOptional.orElseGet(() -> new Student("zz", -1));
System.out.println("student : " + student);
}
輸出結果
結果1:
java.lang.NullPointerException: studentOptional is null
at com.common.java8.OptionalTest.lambda$testOptionalOrElseThrow$7(OptionalTest.java:56)
at java.util.Optional.orElseThrow(Optional.java:290)
at com.common.java8.OptionalTest.testOptionalOrElseThrow(OptionalTest.java:56)...
結果2:
student : Student(name=zz, age=-1)
map()、flatMap()
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));
}
}
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));
}
}
從方法簽名上看,兩者返回參數相同,入參Function的返回參數不一樣,一個是U,一個是Optional< U >, 但是他們都返回Optional< U >
@Test
public void testOptionalMapAndFlatMap() {
Optional<Student> studentOptional = Optional.of(new Student("aa", 11));
System.out.println("map:" + studentOptional.map(Student::getName).orElse(null));
System.out.println("flatMap:" + studentOptional.flatMap(s -> Optional.of(s.getName())).orElse(null));
Optional<Student> nameNullOptional = Optional.of(new Student(null, 11));
System.out.println("map:" + nameNullOptional.map(Student::getName).orElse(null));
System.out.println("flatMap:" + nameNullOptional.flatMap(s -> Optional.ofNullable(s.getName())).orElse(null));
System.out.println("flatMap:" + nameNullOptional.flatMap(s -> null).orElse(null));
}
輸出結果
map:aa
flatMap:aa
map:null
flatMap:null
java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.flatMap(Optional.java:241)
at com.common.java8.OptionalTest.testOptionalMapAndFlatMap(OptionalTest.java:23)
從上面這種用法兩者基本相同。但是在Optional類中,兩個方法真正的區別是flatMap返回的必須是一個非空Optional值,否則會拋出NullPointException.