为了解决空指针的判断问题,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);
}
}
}