Optianal:
主要解决的问题是臭名昭著的空指针异常(NullPointerException) Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。可以使得代码更加的简洁高效。
我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException:
String provinceName = users.getAddress().getProvince().getName();
在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:
if (users!=null){
Address address = users.getAddress();
if (address!=null){
Province province = address.getProvince();
if (province!=null){
String provinceName = province.getName();
}
}
}
这很容易就变得冗长,难以维护。
接下来,进入Optional的学习。
Optional是一个没有子类的工具类,它避免的null值出现空指针异常。
【1】empty():
1):创建一个value值为null的Optional对象。
2): 示例:
Optional<Object> objectOptional = Optional.empty();
System.out.println(objectOptional.isPresent());
System.out.println(objectOptional.isEmpty());
【2】of(T value):
1):value必须是非null值,返回一个Optional对象;
public static <T> Optional<T> of(T value) {
return new Optional(value);
}
2):value如果为空:会报异常(NullPointerException)
Optional name = Optional.of(null);
System.out.println(name);
4):
Optional name = Optional.of("smile");
System.out.println(name);
【3】:ofNullable(T value):
1):如果value为null,它会调用empty方法,如果不为null则调用of方法。
2):
Optional<Object> empty = Optional.empty();
System.out.println("empty()" +" : "+ empty);
Optional<Object> ofNullable = Optional.ofNullable(null);
System.out.println("ofNullable" +" : "+ ofNullable);
Optional<Object> ofNullable_non = Optional.ofNullable("non");
System.out.println("ofNullable_non" +" : "+ ofNullable_non);
【4】:isPresent( );如果这个对象的值不为null返回true,否则返回false。
【5】get():如果这个值存在,则返回这个值,如果这个值为null,则抛出异常;
1):
Optional<String> isPresentMethod = Optional.ofNullable("name");
if (isPresentMethod.isPresent()){
String name = isPresentMethod.get();
System.out.println(name);
}else {
System.out.println("name为空");
}
Optional<String> isPresentMethod_null = Optional.ofNullable(null);
if (isPresentMethod_null.isPresent()){
String name = isPresentMethod_null.get();
}else {
System.out.println("name为空");
}
2):
3): 当传入的value为空时:使用get方法获取value值时,会抛出异常。
Optional<Object> objectOptional = Optional.ofNullable(null);
System.out.println(objectOptional.get());
4):isPresent():还能接收consumer函数式接口,将自己的非空的逻辑写进去。Optioanal该方法更加简洁;
Optional<String> value = Optional.ofNullable("name");
String name = value.get();
value.ifPresent((s)->{
System.out.println(name);
});
【6】ifPresentOrElse()
java 9里新增了 ifPresentOrElse(),当 Optional 里的值不为空则执行第一个参数里的代码,为空则执行第二个参数的代码,相当于 if-else :
Student student = new Student("王五", 80);
Optional<Student> optional = Optional.ofNullable(student);
optional.ifPresentOrElse( value -> System.out.println("student不为空,姓名:"+value.getName()), () -> System.out.println("student为空") );
可以发现当调用get方法获取Value值时,如果value为null,则会抛出NoSuchElementException异常。
为了避免这种情况,可以使用Optianal提供另一个方法
orElse();
【6】orElse() :接收一个参数,如果存在,返回这个值本身,否则返回默认参数。 如果Optional实例有值则将其返回,否则返回orElse方法传入的默认参数。
//如果参数为null,那么name字符串则赋值为空字符串,。
Optional<String> optionalS = Optional.ofNullable(null);
String name = optionalS.orElse("空字符串");
System.out.println(name);
Optional<String> optional2 = Optional.ofNullable("不为空字符串");
String name2 = optional2.orElse("空字符串");
System.out.println(name2);
结果:
【7】:orElseGet():接收一个Supplier,如果存在,返回这个值本身,否则返回Supplier对象。orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
Optional<String> optionalS = Optional.ofNullable(null);
Optional<String> optionalS = Optional.ofNullable(null);
System.out.println(optionalS.orElseGet(new Supplier<String>() {
@Override
public String get() {
return "Default Value";
}
})); //Default Value
Optional<String> optionalS1 = Optional.ofNullable("LeoLi");
System.out.println(optionalS1.orElseGet(()-> "Default Value")); //LeoLi
结果:
【8】orElseThrow():如果有值则将其返回,否则抛出supplier接口创建的异常。
【9】map(): 接收一个Function, 如果Optioanal为null则抛出异常(所以这里创建Optional对象时建议用Optional.ofNullable()),如果为空值则返回空,如果不为空则返回Function的返回值。
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
Optional<String> optionalS1 = Optional.ofNullable("LeoLi");
Optional<Integer> integer = optionalS1.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
System.out.println(integer.orElseGet(()-> 0)); //5
Optional<String> optionalS2 = Optional.ofNullable(null);
Optional<Integer> integer2 = optionalS2.map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
});
System.out.println(integer2.orElseGet(()-> 0)); //0
【10】flatMap : 如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
【注意】:flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。
//通过Optional.ofNullable 创建一个 Optianal对象,即optionalS1 泛型为String
Optional<String> optionalS1 = Optional.ofNullable("leoli");
//利用flatMap 函数 进行类型转化,该函数返回值是 Optional 对象
Optional<Object> objectOptional = optionalS1.flatMap(new Function<String, Optional<?>>() {
@Override
public Optional<?> apply(String s) {
return Optional.of(s.toUpperCase()); //转为大写 LEOLI
}
});
System.out.println(objectOptional.orElseGet(new Supplier<Object>() {
@Override
public Object get() {
return "orElseGet";
}
}));
System.out.println(objectOptional.orElse("orElse"));
【11】filter:
该方法通过传入限定条件对Optional实例的值进行过滤。如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。(对于filter函数我们应该传入实现了Predicate接口的lambda表达式)
Optional<String> name = Optional.of("LeoLi 学习 Optional");
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//输出LeoLi 学习 Optional
Optional<String> name2 = Optional.of("LeoLi");
Optional<String> lessName = name2.filter((value) -> value.length() > 6);
System.out.println(lessName.orElse("The name is less than 6 characters"));//输出The name is less than 6 characters
Optional<String> name3 = Optional.ofNullable("1111111111111111");
Optional<String> Name = name3.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()>6;
}
});
System.out.println(Name.orElse("The name is less than 6 characters"));//输出1111111111111111
注意:
Optioanal 通常作为方法的返回值来使用,它可以有效的规避返回null的结果,如果一个类需要序列化,当Optional作为参数类型或是成员变量类型是有问题的。因为Optional没有实现序列化,所以Optioanl通常不被建议作为参数或常量使用。
示例:
Users users1 = new Users("LeoLi","123",19,null);
Optional<Users> optional = Optional.ofNullable(users1);
Integer integer = optional.map(c -> c.getUsername())
.map(r -> r.length())
.orElse(0);
System.out.println(integer); //5
【11】:ifPresent: 当value 不为空时执行accept方法。
Optional<String> optionalS = Optional.ofNullable("null");
optionalS.ifPresent(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
【12】:ifPresentOrElse: 当value 不为空时执行accept方法。 类似于if-else.
optionalS.ifPresentOrElse(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("内容不为空时执行");
}
}, new Runnable() {
@Override
public void run() {
System.out.println("内容为空时执行");
}
});
//Lambda
optionalS.ifPresentOrElse((c)-> System.out.println("内容不为空时执行"),()-> System.out.println("内容为空时执行"));
三、不适合使用Optional对象的情况
- 不应该用于类的字段,会增加内存消耗,并使序列化变得复杂;
- 不应该用于方法参数,使方法的理解和使用变得复杂;
- 不应用于构造器参数,迫使调用者创建Optional实例,应该通过构造器重载解决;
- 不应该用于集合的参数,集合已经很好的处理空集合的情况,没必要使用Optional包装集合;
- 不建议使用get方法,若为null会报错。
public void givenPresentValue_whenCompare_thenOk() {
User user = new User("john@gmail.com", "1234");
logger.info("Using orElse");
User result = Optional.ofNullable(user).orElse(createNewUser());
logger.info("Using orElseGet");
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}
orElse 和 OrElseGet区别。
这次的输出:
Using orElse
Creating New User
Using orElseGet
这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。**与之相反,orElseGet() 方法不创建 *User对象。