目录
Java中多层对象取值时,为了避免NPE(NullPointerException) ,需要使用object!=null
来进行判断,如果遇到使用场景A.getB().getC()
或Map.get("k1").get("k2")
等类似的情况,层层判空使人头痛(不推荐使用try-catch
,try-catch
本意是捕获异常,性能差,不应该作用于正常的逻辑中)。
实用场景1
import java.util.Optional;
//为A.getB().getC()做准备
class A{
B b = new B() ;
public B getB() {
return b;
}
}
class B{
C c = new C() ;
public C getC() {
return c;
}
}
class C{
int intVal = 1;
public int getIntVal() {
return intVal;
}
};
public class OptionalTest {
public static void main(String[] args) {
//A.getB().getC();
//如果不使用Optional,正常我们如果希望有值就取,无值跳过,不报NPE需要
A a = new A();
if(a.getB()!=null){
B b = a.getB();
if(b.getC()!=null){
C c = b.getC();
System.out.println(c.getIntVal());
}
}
//使用Optional
Optional.ofNullable(a)//判断a是否为空,如果为空返回空Optional不抛异常,否则继续
.map(aa->aa.getB())//a映射为aa
.map(bb->bb.getC())//aa.getB()映射为bb,类似于 bb = aa.getB();
.ifPresent(cc->System.out.println(cc.getIntVal()));//判断如果最终取出C类实例(cc=bb.getC())如果存在,就输出cc的值,全程不抛异常,不用显示判空,有值输出,无值忽略。
/**
*可以将A/B/C类的任意实例赋值为null测试,不会抛异常,注意此场景适用“有值就取,无值就跳过”,不会抛异常!!
*对于嵌套map与嵌套类相似,这里就不再举例
*/
}
}
场景1是笔者认为最实用的场景,没有之一。下面将一一说明Optional
的所有方法使用场景,读者可以根据自己的实际情况单独使用或组合使用。首先准备测试类如下:
public class Person {
private String name;
private int age ;
private int sex;
private Optional<Person> parents;//该字段为了解释说明map方法和flatMap方法的区别,如果是该类型字段,不能使用map方法(会多包一层Optional<Optional<Person>>),
public Person(String name, int age, int sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Optional<Person> getParents() {
return parents == null ? Optional.empty() : parents;
}
public void setParents(Optional<Person> parents) {
this.parents = parents;
}
public String toString() {
return "name=" + name + " , age=" + age + " , sex=" + sex + "{" + parents + "}";
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
}
测试场景2 :ofNullable
ofNullable(obj)
和of(obj)
方法的区别是前者对象为空返回空的Optional
,后者抛异常。
@Test
public void ofNullable_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Optional<Person> personOptional0 = Optional.ofNullable(p0);//空对象返回空Optional不抛异常
Optional<Person> personOptional1 = Optional.ofNullable(p1);
System.out.println("personOptional0: " + personOptional0);
System.out.println("personOptional1: " + personOptional1);
// Optional.of()方法就不再举例,读者自行测试,一测就懂
}
// 输出结果:
// personOptional0: Optional.empty
// personOptional1: Optional[name=p1 , age=10 , sex=1]
与之相关的源码如下:
public final class Optional<T> {
/**
* Optional任何方法产生的空集都返回这个集合
* 因此任何Optional实例调用 empty()或ofNullable(null)方法后相互再使用equals(Object obj)方法比较都会返回true
*/
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
/**
* 该方法返回单例EMPTY,再次强调,注意如果你的Optional最终是空的,都引用的该实例,所有的空Optional相互比较都是true
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
*该构造强制参数不能为空,注意Objects.requireNonNull方法,也是判断类不为空的一种方法(空则抛异常),读者也可以使用。
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
/**
*看到这里就知道为什么of方法抛异常啦
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
*看到这里就知道为什么ofNullable方法不抛异常啦,空value返回单例EMPTY.
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
}
测试场景3 :empty
@Test
public void empty_Method_Test() {
Person p0 = null;
Optional<Person> personOptional0 = Optional.empty();//方式一
System.out.println("personOptional0: " + personOptional0);
personOptional0 = Optional.ofNullable(p0);//方式二
System.out.println("personOptional0: " + personOptional0);
//没有意外的话,方式一和二得到的是同一个Optional对象,如果比较应该返回true,读者自行测试,这里不再测试,源码上文已经提到,不再赘述。
}
// 输出结果
// personOptional0: Optional.empty
// personOptional0: Optional.empty
测试场景4 :equals
@Test
public void equals_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
Optional<Person> personOptional3 = Optional.ofNullable(p1);
Optional<Person> personOptional4 = Optional.ofNullable(p0);
//
System.out.println(personOptional0.equals(personOptional0));//true
System.out.println(personOptional0.equals(personOptional4));//true
System.out.println(personOptional0.equals(Optional.empty()));//true
System.out.println(personOptional1.equals(personOptional2));//false
System.out.println(personOptional1.equals(personOptional3));//true
}
涉及到的源码如下,常规覆写
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
测试场景5 :filter
如果做数据统计和筛选相当有用的一个方法。
@Test
public void filter_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
personOptional0.filter(person -> person.getAge() > 10)//条件筛选
.filter(person -> person.getSex() == 2)//条件筛选
.ifPresent(person -> System.out.println(person));//如果满足条件输出
personOptional1.filter(person -> person.getAge() > 10)
.filter(person -> person.getSex() == 2)
.ifPresent(person -> System.out.println(person));
personOptional2.filter(person -> person.getAge() > 10)
.filter(person -> person.getSex() == 2)
.ifPresent(person -> System.out.println(person));
//优点就是,如果在流式的某一个条件不满足,不用担心下面逻辑是否空异常,非常方便
}
// name=p2 , age=20 , sex=2
相关源码:
/**
* 条件筛选时如果T为空不会报错,可以连续调用
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
测试场景6 :flatMap & map
@Test
public void flatMap_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
personOptional0.flatMap(Person::getParents) //parents实例是Optional<Person>不是Person类型,使用map会报错,此时就需要使用flatMap
.map(Person::getName)//普通字段使用map映射,函数式相当于a->a.getName(),不熟悉可以不用,自行了解
.map(String::trim) // String str = p.getName().trim();
.filter(str -> !"".equals(str)) //条件筛选 null对象会自动过滤,但是""不会,需要我们自己写过滤条件
.ifPresent(person -> System.out.println(person));//如果存在输出
personOptional1.flatMap(Person::getParents)
.map(Person::getName)
.map(String::trim)
.filter(str -> !"".equals(str))
.ifPresent(person -> System.out.println(person));
personOptional2.flatMap(Person::getParents)
.map(Person::getName)
.map(String::trim)
.filter(str -> !"".equals(str))
.ifPresent(person -> System.out.println(personOptional2.get()));
}
// 输出结果:
// name=p2 , age=20 , sex=2{Optional[name=p1 , age=10 , sex=1{null}]}
相关源码:注意,参数类型不一样哦(似乎明白了,又不完全明白)。
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));
}
}
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));
}
}
测试场景7 :get
顾名思义,取出对象,需要注意的是如果对象为空,会抛异常!
test@Test
public void get_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
// System.out.println(personOptional0.get()); 抛异常
System.out.println(personOptional1.get());
System.out.println(personOptional2.get());
}
// 输出结果:
// name=p1 , age=10 , sex=1{null}
// name=p2 , age=20 , sex=2{Optional[name=p1 , age=10 , sex=1{null}]}
相关源码:
/*
* 对象为空直接抛异常:值不存在
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
测试场景8 :hashCode
这是一个众所周知的覆写方法。
@Test
public void hashCode_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);//po2
Optional<Person> personOptional3 = Optional.ofNullable(p2);//po3
System.out.println(personOptional0.hashCode());
System.out.println(personOptional1.hashCode());
System.out.println(personOptional2.hashCode());//spo2
System.out.println(personOptional3.hashCode());//spo3
// po2和po3传同一个对象,所以spo2和spo3输出相同的hashCode
}
// equals 和hashCode方法调用的都是类的方法
// 0
// 136936250
// 593687897
// 593687897
相关源码:
@Override
public int hashCode() {
return Objects.hashCode(value);
}
测试场景9 :ifPresent & isPresent
顾名思义,ifPresent
就是对象如果存在,接下来要做... 相当于if(满足条件){ // TODO 要做的事情}
;isPresent
就是单纯的判断,返回布尔值。
@Test
public void ifPresent_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
personOptional0.ifPresent(person -> System.out.println(person));
personOptional1.ifPresent(person -> System.out.println(person));
personOptional2.ifPresent(person -> System.out.println(person));
System.out.println(personOptional0.isPresent()); //false
System.out.println(personOptional1.isPresent()); //true
System.out.println(personOptional2.isPresent()); //true
}
相关源码:
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
测试场景10 :orElse
顾名思义,如果Optional值为空就赋一个指定值
@Test
public void orElse_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
System.out.println(personOptional0.orElse(new Person("other",43,1)));
System.out.println(personOptional1.orElse(new Person("other",43,1)));
System.out.println(personOptional2.orElse(new Person("other",43,1)));
}
// name=other , age=43 , sex=1{null}
// name=p1 , age=10 , sex=1{null}
// name=p2 , age=20 , sex=2{Optional[name=p1 , age=10 , sex=1{null}]}
相关源码:
//该方法仅仅是赋值而已...
public T orElse(T other) {
return value != null ? value : other;
}
测试场景11 :orElseGet
感觉仅仅就是 orElse 之后 get一下 ...
@Test
public void orElseGet_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
System.out.println(personOptional0.orElseGet(()->new Person("other",11,3)));
System.out.println(personOptional1.orElseGet(()->new Person("other",11,3)));
System.out.println(personOptional2.orElseGet(()->new Person("other",11,3)));
}
相关源码:
// 果然跟我想的一样,就是 orElse 后 get 了一下 ...
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
测试场景12 :orElseThrow
顾名思义,如果值为空就抛异常。
@Test
public void orElseThrow_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
try{
System.out.println(personOptional0.orElseThrow(()-> new NullPointerException("obj is null")));
}catch (NullPointerException e){
e.printStackTrace();
}
try{
System.out.println(personOptional1.orElseThrow(()-> new NullPointerException("obj is null")));
}catch (NullPointerException e){
e.printStackTrace();
}
try{
System.out.println(personOptional2.orElseThrow(()-> new NullPointerException("obj is null")));
}catch (NullPointerException e){
e.printStackTrace();
}
}
// java.lang.NullPointerException: obj is null
// at com.xy.optional.OptionalClassTest.lambda$orElseThrow_Method_Test$21(OptionalClassTest.java:274)
// at java.util.Optional.orElseThrow(Optional.java:290)
// at com.xy.optional.OptionalClassTest.orElseThrow_Method_Test(OptionalClassTest.java:274)
// at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
// ...
// name=p1 , age=10 , sex=1{null}
// name=p2 , age=20 , sex=2{Optional[name=p1 , age=10 , sex=1{null}]}
相关源码:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
测试场景13 :toString
不言
@Test
public void toString_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
p2.setParents(Optional.of(p1));
Optional<Person> personOptional0 = Optional.ofNullable(p0);
Optional<Person> personOptional1 = Optional.ofNullable(p1);
Optional<Person> personOptional2 = Optional.ofNullable(p2);
System.out.println(personOptional0.toString());
System.out.println(personOptional1.toString());
System.out.println(personOptional2.toString());
}
// Optional.empty
// Optional[name=p1 , age=10 , sex=1{null}]
// Optional[name=p2 , age=20 , sex=2{Optional[name=p1 , age=10 , sex=1{null}]}]
不语
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}