Coding With Fun
Home Docker Django Node.js Articles FAQ

Come on, don't use it again!


May 31, 2021 Article blog


Table of contents


null is a headache for Java programmers. Y ou are often harassed by empty pointer exceptions (NPE). Even the inventor of Java admits it was a huge mistake.

So, what's the way to avoid writing a lot of empty statements in your code?

Some people say you can use the Optional provided by JDK8 to avoid a short sentence, but it's a bit of a hassle to use.

In his daily work, the author encapsulates a tool that calls object members in chains without emptying them, making it more elegant and easy to use than the original if null logic and JDK8 Optional, greatly improving coding efficiency in engineering practice, and making the code more accurate and elegant.

Unseemly judgment air conditioning

I think the little partner in Java development must have encountered this uncomfortable judgment logic: now there is a User class, and School is its member variable

/**


* @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;


    }


}

Now you want to get School's member variable adress, the general way to handle it:

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());


    }


}

It's a bit of a hassle to judge School when you get adress, and while it's a bit of a hassle, it's a bit of a hassle, and it's a bit of a hassle, as is the Optional tool available through JDK8.

The OptionalBean below provides a way to continuously call member variables without emptying them, directly chaining to the target variable you want to get without worrying about empty pointers.

The member variable is called in a chain

If you use the tool OptionalBean designed for this article, the above call can be simplified to this:

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);


}

Execution results:

 Come on, don't use it again!1

Where The User'S Schol Variable Is Empty, You Can See That The Code Does Not Have An Empty Pointer, But ReturnS The null. How does this tool work?

OptionalBean tool

/**


* @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;


    }


}

The tool design refers primarily to the implementation of Optional, plus the extension of the chain call is the OptionBean above.

GetBean is actually an OptionalBean object that wraps an empty value when the variable is empty, and generics are used to make the tool easier to use.

Manual

You can see that the same extension methods as Optional are available in the code, such as ifPresent(), orElse(), and so on:

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());


    }


}

Run:

 Come on, don't use it again!2

summary

A tool designed to call object members in a chain without having to be empty makes the code more precise and elegant, and if the tool designed in this article satisfies just to solve your problem, use it in your project!

This article comes from the public number: Hollis, author: God loves apples

Above is W3Cschool编程狮 about please, don't use it again! Related to the introduction, I hope to help you.