Java Null判断的替代方法

为了解决空指针的判断问题,Java引入了Optional、Objects等工具。
但平时比较费事的是对象以及对象属性的多级判断。
前几天看了一篇博文,作者通过借鉴Optional实现了多级null判断,这里自己也实现一下,且通过Junit5编写了测试用例。
github源码工程

Optional代码:

package org.yunzhong.CommonTest.util;

import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author yunzhong
 *
 * @param <T>
 */
public final class OptionalUtil<T> {

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

    private final T value;

    private OptionalUtil() {
        this.value = null;
    }

    public OptionalUtil(T value) {
        this.value = value;
    }

    public static <T> OptionalUtil<T> of(T value) {
        return new OptionalUtil<>(Objects.requireNonNull(value));
    }

    /**
     * @param <T>
     * @param value
     * @return
     */
    public static <T> OptionalUtil<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 
     * 取出具体的值
     * 
     * @param fn
     * @param <R>
     * @return
     */

    public T get() {
        return value;
    }

    /**
     * 
     * 取出一个可能为空的对象
     * 
     * @param fn
     * @param <R> * @return
     */

    public <R> OptionalUtil<R> getProperty(Function<? super T, ? extends R> fn) {
        return Objects.isNull(value) ? OptionalUtil.empty() : OptionalUtil.ofNullable(fn.apply(value));
    }

    /**
     * 如果目标值不为空,返回value。<br>
     * 如果目标值为空,返回传入的默认值
     * 
     * @param defaultValue
     * @return
     */

    public T orElse(T defaultValue) {
        return value != null ? value : defaultValue;
    }

    /**
     * 如果目标值不为空,返回value。<br>
     * 如果目标值为空 通过lambda表达式获取一个值
     * 
     * @param defaultSupplier
     * @return
     */

    public T orElseGet(Supplier<? extends T> defaultSupplier) {
        return value != null ? value : defaultSupplier.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;
    }

    /**
     * @param consumer
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    public OptionalUtil<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent()) {
            return this;
        } else {
            return predicate.test(value) ? this : empty();
        }
    }

    /**
     * 空值常量
     * 
     * @param <T> * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> OptionalUtil<T> empty() {
        OptionalUtil<T> none = (OptionalUtil<T>) EMPTY;
        return none;
    }
}

测试用例:

package org.yunzhong.CommonTest.util;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

@DisplayName("optional单元测试")
public class OptionalUtilTest {

    @BeforeAll
    public static void beforeAll() {
        System.out.println("first of all.");
    }

    @AfterAll
    public static void afterAll() {
        System.out.println("after of all.");
    }

    @Nested
    @DisplayName("of方法单元测试")
    class OfTest {

        @Test
        @DisplayName("of方法正常")
        void testOf() {
            OptionalUtil<Double> value = OptionalUtil.of(Double.valueOf(12.2));
            assertNotNull(value);
            assertEquals(12.2, value.get(), 1);
        }

        @Test
        @DisplayName("of方法null抛出异常")
        void testOfWithNull() {
            NullPointerException exception = assertThrows(NullPointerException.class, () -> OptionalUtil.of(null));
            assertNotNull(exception);
        }
    }

    @Nested
    @DisplayName("ofNullable方法单元测试")
    class OfNullableTest {

        @Test
        @DisplayName("ofNullable方法正常")
        void testOf() {
            OptionalUtil<Double> value = OptionalUtil.ofNullable(Double.valueOf(12.2));
            assertNotNull(value);
            assertEquals(12.2, value.get(), 1);
        }

        @Test
        @DisplayName("ofNullable方法null,get返回null")
        void testOfWithNull() {
            Object value = OptionalUtil.ofNullable(null).get();
            assertNull(value);
        }
    }

    @Nested
    @DisplayName("getProperty方法单元测试")
    class GetPropertyTest {
        class TestModel {
            private String id;
            private String name;
            private TestModel model;

            public String getId() {
                return id;
            }

            public void setId(String id) {
                this.id = id;
            }

            public String getName() {
                return name;
            }

            public void setName(String name) {
                this.name = name;
            }

            public TestModel getModel() {
                return model;
            }

            public void setModel(TestModel model) {
                this.model = model;
            }

        }

        @Test
        @DisplayName("getProperty方法正常")
        void testgetProperty() {
            TestModel model = new TestModel();
            model.setId("id1");
            model.setName("name1");
            TestModel modelInner = new TestModel();
            modelInner.setId("innerId");
            modelInner.setName("innerName");
            model.setModel(modelInner);

            String result = OptionalUtil.ofNullable(model).getProperty(TestModel::getModel)
                    .getProperty(TestModel::getId).get();
            assertEquals("innerId", result);
        }

        @Test
        @DisplayName("getProperty方法null,get返回null")
        void testgetPropertyNull() {
            TestModel model = new TestModel();
            model.setId("id1");
            model.setName("name1");

            String result = OptionalUtil.ofNullable(model).getProperty(TestModel::getModel)
                    .getProperty(TestModel::getId).get();
            assertNull(result);
        }
    }

    @Test
    @DisplayName("OrElse方法")
    void testOrElse() {
        Double orElse = OptionalUtil.ofNullable(Double.valueOf(12)).orElse(100.0);
        assertEquals(12, orElse, 0);
        Double param = null;
        Double orElse2 = OptionalUtil.ofNullable(param).orElse(100.0D);
        assertEquals(100, orElse2, 0);
    }

    @Test
    @DisplayName("OrElseGet方法")
    void testOrElseGet() {
        Double orElse = OptionalUtil.ofNullable(Double.valueOf(12)).orElseGet(() -> {
            return 10 * 12D;
        });
        assertEquals(12, orElse, 0);
        Double param = null;
        Double orElse2 = OptionalUtil.ofNullable(param).orElseGet(() -> {
            return 10 * 12D;
        });
        assertEquals(120, orElse2, 0);
    }

    @Test
    @DisplayName("OrElseThrow单元测试")
    void testOrElseThrow() {
        Double param = null;
        NullPointerException assertThrows = assertThrows(NullPointerException.class,
                () -> OptionalUtil.ofNullable(param).orElseThrow(() -> new NullPointerException()));
        assertNotNull(assertThrows);
    }

    @Test
    @DisplayName("IsPresent单元测试")
    void testIsPresent() {
        boolean present = OptionalUtil.ofNullable(Double.valueOf(33)).isPresent();
        assertEquals(true, present);
        present = OptionalUtil.ofNullable(null).isPresent();
        assertEquals(false, present);
    }

    @Test
    @DisplayName("IfPresent单元测试")
    void testIfPresent() {
        OptionalUtil.ofNullable(Double.valueOf(33)).ifPresent((value) -> {
            System.out.println(value);
        });
    }

    @Nested
    @DisplayName("Filter单元测试")
    class FilterTest {

        @Test
        @DisplayName("Filter null 单元测试")
        void testFilterNull() {
            Object result = OptionalUtil.ofNullable(null).filter((value) -> {
                if (value == null) {
                    return true;
                } else {
                    return false;
                }
            }).get();
            assertNull(result);
        }

        @Test
        @DisplayName("Filter null 单元测试")
        void testFilter() {
            Double param = 100D;
            Double result = OptionalUtil.ofNullable(param).filter((value) -> {
                if (value > 10) {
                    return true;
                } else {
                    return false;
                }
            }).get();
            assertEquals(100D, result, 1);

            param = 3D;
            result = OptionalUtil.ofNullable(param).filter((value) -> {
                if (value > 10) {
                    return true;
                } else {
                    return false;
                }
            }).get();
            assertNull(result);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值