diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java index d86c3e03b..1648e404e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/Opt.java @@ -26,13 +26,13 @@ package cn.hutool.core.lang; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.func.Func0; -import cn.hutool.core.lang.func.VoidFunc0; import cn.hutool.core.text.StrUtil; -import java.util.Collection; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; +import java.util.Collection; +import java.util.Collections; +import java.util.NoSuchElementException; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -92,11 +92,10 @@ public class Opt { * 返回一个包裹里元素可能为空的{@code Opt},额外判断了空字符串的情况 * * @param value 传入需要包裹的元素 - * @param 包裹里元素的类型 * @return 一个包裹里元素可能为空,或者为空字符串的 {@code Opt} */ - public static Opt ofBlankAble(final T value) { - return StrUtil.isBlankIfStr(value) ? empty() : new Opt<>(value); + public static Opt ofBlankAble(final CharSequence value) { + return StrUtil.isBlank(value) ? empty() : new Opt<>(value); } /** @@ -109,7 +108,7 @@ public class Opt { * @since 5.7.17 */ public static > Opt ofEmptyAble(final R value) { - return CollUtil.isEmpty(value) ? empty() : new Opt<>(value); + return CollUtil.isEmpty(value) || Objects.equals(Collections.frequency(value, null), value.size()) ? empty() : new Opt<>(value); } /** @@ -217,56 +216,6 @@ public class Opt { return this; } - /** - * 如果包裹里的值存在,就执行传入的值存在时的操作({@link Consumer#accept}) - * 否则执行传入的值不存在时的操作({@link VoidFunc0}中的{@link VoidFunc0#call()}) - * - *

- * 例如值存在就打印对应的值,不存在则用{@code Console.error}打印另一句字符串 - *

{@code
-	 * Opt.ofNullable("Hello Hutool!").ifPresentOrElse(Console::log, () -> Console.error("Ops!Something is wrong!"));
-	 * }
- * - * @param action 包裹里的值存在时的操作 - * @param emptyAction 包裹里的值不存在时的操作 - * @return this; - * @throws NullPointerException 如果包裹里的值存在时,执行的操作为 {@code null}, 或者包裹里的值不存在时的操作为 {@code null},则抛出{@code NPE} - */ - public Opt ifPresentOrElse(final Consumer action, final VoidFunc0 emptyAction) { - if (isPresent()) { - action.accept(value); - } else { - emptyAction.callWithRuntimeException(); - } - return this; - } - - - /** - * 如果包裹里的值存在,就执行传入的值存在时的操作({@link Function#apply(Object)})支持链式调用、转换为其他类型 - * 否则执行传入的值不存在时的操作({@link VoidFunc0}中的{@link VoidFunc0#call()}) - * - *

- * 如果值存在就转换为大写,否则用{@code Console.error}打印另一句字符串 - *

{@code
-	 * String hutool = Opt.ofBlankAble("hutool").mapOrElse(String::toUpperCase, () -> Console.log("yes")).mapOrElse(String::intern, () -> Console.log("Value is not present~")).get();
-	 * }
- * - * @param map后新的类型 - * @param mapper 包裹里的值存在时的操作 - * @param emptyAction 包裹里的值不存在时的操作 - * @return 新的类型的Opt - * @throws NullPointerException 如果包裹里的值存在时,执行的操作为 {@code null}, 或者包裹里的值不存在时的操作为 {@code null},则抛出{@code NPE} - */ - public Opt mapOrElse(final Function mapper, final VoidFunc0 emptyAction) { - if (isPresent()) { - return ofNullable(mapper.apply(value)); - } else { - emptyAction.callWithRuntimeException(); - return empty(); - } - } - /** * 判断包裹里的值存在并且与给定的条件是否满足 ({@link Predicate#test}执行结果是否为true) * 如果满足条件则返回本身 @@ -359,12 +308,7 @@ public class Opt { * @author VampireAchao */ public Opt peek(final Consumer action) throws NullPointerException { - Objects.requireNonNull(action); - if (isEmpty()) { - return Opt.empty(); - } - action.accept(value); - return this; + return ifPresent(action); } @@ -382,8 +326,7 @@ public class Opt { */ @SafeVarargs public final Opt peeks(final Consumer... actions) throws NullPointerException { - // 第三个参数 (opts, opt) -> null其实并不会执行到该函数式接口所以直接返回了个null - return Stream.of(actions).reduce(this, Opt::peek, (opts, opt) -> null); + return peek(Stream.of(actions).reduce(Consumer::andThen).orElseGet(() -> o -> {})); } /** @@ -455,6 +398,22 @@ public class Opt { return isPresent() ? value : supplier.get(); } + /** + * 如果包裹里元素的值存在,则返回该值,否则执行传入的操作 + * + * @param action 值不存在时执行的操作 + * @return 如果包裹里元素的值存在,则返回该值,否则执行传入的操作 + * @throws NullPointerException 如果值不存在,并且传入的操作为 {@code null} + */ + public T orElseRun(Runnable action) { + if (isPresent()) { + return value; + } else { + action.run(); + return null; + } + } + /** * 如果包裹里的值存在,则返回该值,否则抛出 {@code NoSuchElementException} * @@ -462,7 +421,7 @@ public class Opt { * @throws NoSuchElementException 如果包裹里的值不存在则抛出该异常 */ public T orElseThrow() { - return orElseThrow(NoSuchElementException::new, "No value present"); + return orElseThrow(() -> new NoSuchElementException("No value present")); } /** @@ -483,30 +442,6 @@ public class Opt { } } - /** - * 如果包裹里的值存在,则返回该值,否则执行传入的操作,获取异常类型的返回值并抛出 - * - *

往往是一个包含 自定义消息 构造器的异常 例如 - *

{@code
-	 * 		Opt.ofNullable(null).orElseThrow(IllegalStateException::new, "Ops!Something is wrong!");
-	 * }
- * - * @param 异常类型 - * @param exceptionFunction 值不存在时执行的操作,返回值继承 {@link Throwable} - * @param message 作为传入操作执行时的参数,一般作为异常自定义提示语 - * @return 包裹里不能为空的值 - * @throws X 如果值不存在 - * @throws NullPointerException 如果值不存在并且 传入的操作为 {@code null}或者操作执行后的返回值为{@code null} - * @author VampireAchao - */ - public T orElseThrow(final Function exceptionFunction, final String message) throws X { - if (isPresent()) { - return value; - } else { - throw exceptionFunction.apply(message); - } - } - /** * 转换为 {@link Optional}对象 * diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java index bcceae3dc..a80dd8636 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/OptTest.java @@ -9,6 +9,9 @@ import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -45,19 +48,6 @@ public class OptTest { Assert.assertTrue(isEmpty); } - @Test - @Ignore - public void ifPresentOrElseTest() { - // 存在就打印对应的值,不存在则用{@code System.err.println}打印另一句字符串 - Opt.ofNullable("Hello Hutool!").ifPresentOrElse(Console::log, () -> Console.error("Ops!Something is wrong!")); - - Opt.empty().ifPresentOrElse(Console::log, () -> Console.error("Ops!Something is wrong!")); - - // 拓展为支持链式调用 - Opt.empty().ifPresentOrElse(Console::log, () -> Console.error("Ops!Something is wrong!")) - .ifPresentOrElse(Console::log, () -> Console.error("Ops!Something is wrong!")); - } - @Test public void peekTest() { final User user = new User(); @@ -127,11 +117,16 @@ public class OptTest { Assert.assertNull(assignException); } - @Test(expected = IllegalStateException.class) - public void orElseThrowTest3() { - // 获取一个不可能为空的值,否则抛出带自定义消息的自定义异常 - final Object exceptionWithMessage = Opt.empty().orElseThrow(IllegalStateException::new, "Ops!Something is wrong!"); - Assert.assertNull(exceptionWithMessage); + @Test + public void orElseRunTest() { + // 判断一个值是否为空,为空执行一段逻辑,否则执行另一段逻辑 + Map map = new HashMap<>(); + final String key = "key"; + map.put(key, 1); + Opt.ofNullable(map.get(key)) + .ifPresent(v -> map.put(key, v + 1)) + .orElseRun(() -> map.remove(key)); + Assert.assertEquals((Object) 2, map.get(key)); } @Test @@ -155,14 +150,8 @@ public class OptTest { // 现在,一个ofEmptyAble搞定 final List hutool = Opt.ofEmptyAble(Collections.emptyList()).orElseGet(() -> Collections.singletonList("hutool")); Assert.assertEquals(past, hutool); - Assert.assertEquals(hutool, Collections.singletonList("hutool")); - } - - @Test - public void mapOrElseTest() { - // 如果值存在就转换为大写,否则打印一句字符串,支持链式调用、转换为其他类型 - final String hutool = Opt.ofBlankAble("hutool").mapOrElse(String::toUpperCase, () -> Console.log("yes")).mapOrElse(String::intern, () -> Console.log("Value is not present~")).get(); - Assert.assertEquals("HUTOOL", hutool); + Assert.assertEquals(Collections.singletonList("hutool"), hutool); + Assert.assertTrue(Opt.ofEmptyAble(Arrays.asList(null, null, null)).isEmpty()); } @SuppressWarnings({"MismatchedQueryAndUpdateOfCollection", "ConstantConditions"})