最近真的被NPE问题烦死了,于是准备学习Optional大杀器解决这个问题!
当我们有两个POJO并且有这样的关联时
public class User{
private Address address;
}
class Address{
private String province;
}
我们可能有这样的代码
if(user != null){
Address address = user.getAddress();
if(address != null){
String province = address.getProvince();
}
}
写起来代码又冗余又丑陋,那么我们怎样才能解决这么丑陋的代码呢,提升开发效能呢???我们需要Optional!!!
创建Optional实例
我们看Optional的源码,发现Optional的构造方法是private的,只可以用of和ofNullable,那它们有什么区别呢?
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
通过源码我们发现如果使用of创建Optional实例,假设我们传入的是null,那么还是会报NPE异常,而如果使用ofNullable,则会返回一个empty对象。那是不是说我们以后就用ofNullable不用of了呢???,其实它们存在都是合理的都有应用场景(但这个场景真的很少。。。起码我没遇到过)
orElse orElseGet orElseThrow
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
从这三个函数的源码可以发现,当入参不为null时,会返回入参值,否则返回orElsexxx里的值
public class TestOptional {
public static void main(String[] args) {
User user = null;
User userByOrElse = Optional.ofNullable(user).orElse(createUser());
User userByOrElseGet = Optional.ofNullable(user).orElseGet(() -> createUser());
System.out.println(userByOrElse.getName());
System.out.println(userByOrElseGet.getName());
System.out.println("***************");
User user1 = new User("frank");
User user1ByOrElse = Optional.ofNullable(user1).orElse(createUser());
User user1ByOrElseGet = Optional.ofNullable(user1).orElseGet(() -> createUser());
System.out.println(user1ByOrElse.getName());
System.out.println(user1ByOrElseGet.getName());
}
public static User createUser(){
System.out.println("---");
return new User("Song X.");
}
}
经过测试发现了当入参不为null时,orElse依旧会执行createUser(尽管返回的还是原参),而orElseGet则不会执行createUser了。所以这样看起来orElseGet相对来说少创建了一个无用对象,性能更好
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的输出,所以User的结构是如下时
public class User{
private String name;
public String getName(){
return name;
}
}
使用
User user = new User("zhangsan");
String s = Optional.ofNullable(user).map((u) -> u.getName()).get();
如果User的结构是如下时
public class User{
private String name;
public Optional<String> getName() {
return Optional.ofNullable(name);
}
}
使用
String s = Optional.ofNullable(user).flatMap(u -> u.getName()).get();
isPresent ifPresent
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
isPresent就是用来判断当前值是否为null,如果不为null再用ifPresent做一些操作,所以你肯定能写出下面的代码。可是if(user.isPresnet())和if(user != null) 又有什么区别呢,所以这肯定不是Optional的正确姿势
public static void main(String[] args) {
Optional<User> user = Optional.ofNullable(new User("zhangsan"));
if(user.isPresent()){
user.ifPresent(u -> u.setName("Song X."));
}
System.out.println(user.get().getName());
}
filter
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
filter顾名思义就是做数据清洗的了,如果入参不是null就会根据对应的Predicate做操作,不然就返回empty
Optional<User> zhangsan = Optional.ofNullable(new User("zhangsan"));
Optional<User> lisi = Optional.ofNullable(new User("lisi"));
Optional<User> filteredZhangsan = zhangsan.filter(u -> u.getName().length() > 5);
Optional<User> filteredlisi = lisi.filter(u -> u.getName().length() > 5);
System.out.println(filteredZhangsan.get().getName());
System.out.println(filteredlisi.get().getName());
实战写法,彻底解决NPE
1
一开始的代码
if(user != null){
Address address = user.getAddress();
if(address != null){
String province = address.getProvince();
}
}
我们就可以改写为
Optional.ofNullable(user)
.map(user -> user.getAddress())
.map(addr -> addr.getProvince)
2
if(user != null){
//dosomething(user)
}
可以改写为
Optional.ofNullable(user)
.ifPresent(u -> dosomething(u));
3
我们以前可能会这么写
public static User getUser(User user){
if(user != null){
String name = user.getName();
if(Objects.equals("Song X.", name)){
return user;
}
}else {
return new User("Song X.");
}
return null;
}
现在我们可以这么写
public static User getUserByOptional(User user){
return Optional.ofNullable(user)
.filter(u -> Objects.equals("Song X.", u.getName()))
.orElseGet(() -> new User("Song X."));
}