温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么避免在Java代码中写大量的判空语句

发布时间:2022-03-01 13:53:54 来源:亿速云 阅读:316 作者:iii 栏目:开发技术

这篇文章主要介绍了怎么避免在Java代码中写大量的判空语句的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么避免在Java代码中写大量的判空语句文章都会有所收获,下面我们一起来看看吧。

有人说可以使用 JDK8提供的 Optional 来避免判空,但是用起来还是有些麻烦。

作者在日常工作中,封装了一个工具,可以链式调用对象成员而无需判空,相比原有的if null逻辑 和 JDK8提供的 Optional 更加优雅易用,在工程实践中大大提高了编码效率,也让代码更加的精准和优雅。

不优雅的判空调用

我想从事 Java 开发的小伙伴肯定有遇到过下面这种让人难受的判空逻辑:现在有一个User类,School 是它的成员变量

/**


* @author Axin


* @since 2020-09-20


* @summary 一个User类定义


 * (Ps:Data 是lombok组件提供的注解,简化了get set等等的约定代码)


*/


@Data


public class User {


    private String name;


    private String gender;


    private School school;


    @Data


    public static class School {


        private String scName;


        private String adress;


    }


}

现在想要获得School的成员变量 adress , 一般的处理方式:

public static void main(String[] args) {


    User axin = new User();


    User.School school = new User.School();


    axin.setName("hello");


    if (Objects.nonNull(axin) && Objects.nonNull(axin.getSchool())) {


        User.School userSc = axin.getSchool();


        System.out.println(userSc.getAdress());


    }


}

获取 adress 时要对 School 进行判空,虽然有些麻烦,到也能用,通过 JDK8 提供的 Optional 工具也是可以,但还是有些麻烦。

而下文的 OptionalBean 提供一种可以链式不断地调用成员变量而无需判空的方法,直接链式调用到你想要获取的目标变量,而无需担心空指针的问题。

链式调用成员变量

如果用了本文设计的工具 OptionalBean ,那么上述的调用可以简化成这样:

public static void main(String[] args) {


    User axin = new User();


    User.School school = new User.School();


    axin.setName("hello");


    // 1. 基本调用


    String value1 = OptionalBean.ofNullable(axin)


            .getBean(User::getSchool)


            .getBean(User.School::getAdress).get();


    System.out.println(value1);


}

执行结果:

怎么避免在Java代码中写大量的判空语句

其中User的school变量为空,可以看到代码并没有空指针,而是返回了null。这个工具怎么实现的呢?

OptionalBean 工具

/**


* @author Axin


* @since 2020-09-10


* @summary 链式调用 bean 中 value 的方法


*/


public final class OptionalBean<T> {


    private static final OptionalBean<?> EMPTY = new OptionalBean<>();


    private final T value;


    private OptionalBean() {


        this.value = null;


    }


    /**


     * 空值会抛出空指针


     * @param value


     */


    private OptionalBean(T value) {


        this.value = Objects.requireNonNull(value);


    }


    /**


     * 包装一个不能为空的 bean


     * @param value


     * @param <T>


     * @return


     */


    public static <T> OptionalBean<T> of(T value) {


        return new OptionalBean<>(value);


    }


    /**


     * 包装一个可能为空的 bean


     * @param value


     * @param <T>


     * @return


     */


    public static <T> OptionalBean<T> ofNullable(T value) {


        return value == null ? empty() : of(value);


    }


    /**


     * 取出具体的值


     * @param fn


     * @param <R>


     * @return


     */


    public T get() {


        return Objects.isNull(value) ? null : value;


    }


    /**


     * 取出一个可能为空的对象


     * @param fn


     * @param <R>


     * @return


     */


    public <R> OptionalBean<R> getBean(Function<? super T, ? extends R> fn) {


        return Objects.isNull(value) ? OptionalBean.empty() : OptionalBean.ofNullable(fn.apply(value));


    }


    /**


     * 如果目标值为空 获取一个默认值


     * @param other


     * @return


     */


    public T orElse(T other) {


        return value != null ? value : other;


    }


    /**


     * 如果目标值为空 通过lambda表达式获取一个值


     * @param other


     * @return


     */


    public T orElseGet(Supplier<? extends T> other) {


        return value != null ? value : other.get();


    }


    /**


     * 如果目标值为空 抛出一个异常


     * @param exceptionSupplier


     * @param <X>


     * @return


     * @throws X


     */


    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {


        if (value != null) {


            return value;


        } else {


            throw exceptionSupplier.get();


        }


    }


    public boolean isPresent() {


        return value != null;


    }


    public void ifPresent(Consumer<? super T> consumer) {


        if (value != null)


            consumer.accept(value);


    }


    @Override


    public int hashCode() {


        return Objects.hashCode(value);


    }


    /**


     * 空值常量


     * @param <T>


     * @return


     */


    public static<T> OptionalBean<T> empty() {


        @SuppressWarnings("unchecked")


        OptionalBean<T> none = (OptionalBean<T>) EMPTY;


        return none;


    }


}

工具设计主要参考了 Optional 的实现,再加上对链式调用的扩展就是上述的OptionalBean。

getBean 其实是当变量为空时返回了一个 包装空值的 OptionalBean 对象,同时泛型的使用让工具更加易用。

使用手册

可以看到代码中也提供了和 Optional 一样的扩展方法,如 ifPresent()、orElse()等等:

public static void main(String[] args) {


    User axin = new User();


    User.School school = new User.School();


    axin.setName("hello");


    // 1. 基本调用


    String value1 = OptionalBean.ofNullable(axin)


            .getBean(User::getSchool)


            .getBean(User.School::getAdress).get();


    System.out.println(value1);


    // 2. 扩展的 isPresent方法 用法与 Optional 一样


    boolean present = OptionalBean.ofNullable(axin)


            .getBean(User::getSchool)


            .getBean(User.School::getAdress).isPresent();


    System.out.println(present);


    // 3. 扩展的 ifPresent 方法


    OptionalBean.ofNullable(axin)


            .getBean(User::getSchool)


            .getBean(User.School::getAdress)


            .ifPresent(adress -> System.out.println(String.format("地址存在:%s", adress)));


    // 4. 扩展的 orElse


    String value2 = OptionalBean.ofNullable(axin)


            .getBean(User::getSchool)


            .getBean(User.School::getAdress).orElse("家里蹲");


    System.out.println(value2);


    // 5. 扩展的 orElseThrow


    try {


        String value3 = OptionalBean.ofNullable(axin)


                .getBean(User::getSchool)


                .getBean(User.School::getAdress).orElseThrow(() -> new RuntimeException("空指针了"));


    } catch (Exception e) {


        System.out.println(e.getMessage());


    }


}

关于“怎么避免在Java代码中写大量的判空语句”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“怎么避免在Java代码中写大量的判空语句”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI