JavaSE——Optional类的正确用法,终于搞定NPE问题!

最近真的被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."));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值