目录
实用场景1
测试场景2 :ofNullable
测试场景3 :empty
测试场景4 :equals
测试场景5 :filter
测试场景6 :flatMap & map
测试场景7 :get
测试场景8 :hashCode
测试场景9 :ifPresent & isPresent
测试场景10 :orElse
测试场景11 :orElseGet
测试场景12 :orElseThrow
测试场景13 :toString
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的值,全程不抛异常,不用显示判空,有值输出,无值忽略。
}
}
场景1是笔者认为最实用的场景,没有之一。下面将一一说明Optional的所有方法使用场景,读者可以根据自己的实际情况单独使用或组合使用。首先准备测试类如下:
public class Person {
private String name;
private int age ;
private int sex;
private Optional parents;//该字段为了解释说明map方法和flatMap方法的区别,如果是该类型字段,不能使用map方法(会多包一层Optional>),
public Person(String name, int age, int sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Optional getParents() {
return parents == null ? Optional.empty() : parents;
}
public void setParents(Optional 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 personOptional0 = Optional.ofNullable(p0);//空对象返回空Optional不抛异常
Optional 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{ private static final Optional> EMPTY = new Optional<>(); private final T value; private Optional() { this.value = null; } public static Optional empty() { @SuppressWarnings("unchecked") Optional t = (Optional ) EMPTY; return t; } private Optional(T value) { this.value = Objects.requireNonNull(value); } public static Optional of(T value) { return new Optional<>(value); } public static Optional ofNullable(T value) { return value == null ? empty() : of(value); } }
测试场景3 :empty
@Test
public void empty_Method_Test() {
Person p0 = null;
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional personOptional2 = Optional.ofNullable(p2);
Optional personOptional3 = Optional.ofNullable(p1);
Optional 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
}
@Test
public void equals_Method_Test() {
Person p0 = null;
Person p1 = new Person("p1", 10, 1);
Person p2 = new Person("p2", 20, 2);
Optional personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional personOptional2 = Optional.ofNullable(p2);
Optional personOptional3 = Optional.ofNullable(p1);
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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
相关源码:
public Optionalfilter(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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional personOptional2 = Optional.ofNullable(p2);
personOptional0.flatMap(Person::getParents) //parents实例是Optional不是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 Optional flatMap(Function super T, Optional> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
public Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional personOptional2 = Optional.ofNullable(p2);//po2
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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}]}
相关源码:
publicT 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 personOptional0 = Optional.ofNullable(p0);
Optional personOptional1 = Optional.ofNullable(p1);
Optional 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";
}



