Browse Source

Merge pull request #1182 from totalo/v5-dev

feat:优雅判空
Golden Looly 5 years ago
parent
commit
02c97eedde

+ 130 - 0
hutool-core/src/main/java/cn/hutool/core/bean/OptionalBean.java

@@ -0,0 +1,130 @@
+package cn.hutool.core.bean;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * optional 判空
+ * @param <T>
+ * @author totalo
+ * @since 5.4.7
+ * @see https://mp.weixin.qq.com/s/0c8iC0OTtx5LqPkhvkK0tw
+ */
+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);
+    }
+
+    /**
+     * 取出具体的值
+     * @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;
+    }
+}

+ 49 - 0
hutool-core/src/test/java/cn/hutool/core/bean/OptionalBeanTest.java

@@ -0,0 +1,49 @@
+package cn.hutool.core.bean;
+
+import org.junit.Assert;
+import lombok.Data;
+import org.junit.Test;
+
+public class OptionalBeanTest {
+
+    @Test
+    public void OptionalBeanTest() {
+        User user = new User();
+        user.setName("hello");
+        String value1 = OptionalBean.ofNullable(user)
+                .getBean(User::getSchool)
+                .getBean(User.School::getAddress).get();
+        Assert.assertEquals(value1, null);
+
+        boolean present = OptionalBean.ofNullable(user)
+                .getBean(User::getSchool)
+                .getBean(User.School::getAddress).isPresent();
+        Assert.assertFalse(present);
+
+        String value2 = OptionalBean.ofNullable(user)
+                .getBean(User::getSchool)
+                .getBean(User.School::getAddress).orElse("没得地址");
+        Assert.assertEquals(value2, "没得地址");
+        try {
+            OptionalBean.ofNullable(user)
+                    .getBean(User::getSchool)
+                    .getBean(User.School::getAddress).orElseThrow(() -> new RuntimeException("空指针了"));
+        } catch (Exception e) {
+            Assert.assertEquals(e.getMessage(), "空指针了");
+        }
+    }
+
+
+    @Data
+    public class User {
+        private String name;
+        private String gender;
+        private School school;
+        @Data
+        public class School {
+            private String name;
+            private String address;
+        }
+    }
+
+}