gpt4 book ai didi

java - 以功能方式处理异常的更好方法

转载 作者:IT老高 更新时间:2023-10-28 20:23:44 25 4
gpt4 key购买 nike

当在 Java 8 中使用 FP 习语时,异常,尤其是已检查的异常,会严重中断程序逻辑的流程。下面是一个任意示例:

String s1 = "oeu", s2 = "2";
Stream.of(s1, s2).forEach(s ->
System.out.println(Optional.of(s).map(Integer::parseInt).get()));

当无法解析的字符串出现异常时,上面的代码会中断。但是假设我只想用默认值替换它,就像我可以使用 Optional:

Stream.of(s1, s2).forEach(s -> 
System.out.println(Optional.of(s)
.map(Integer::parseInt)
.orElse(-1)));

当然,这仍然失败,因为 Optional 只处理 null。我想要以下内容:

Stream.of(s1, s2).forEach(s ->
System.out.println(
Exceptional.of(s)
.map(Integer::parseInt)
.handle(NumberFormatException.class, swallow())
.orElse(-1)));

注意:这是一个 self 回答的问题。

最佳答案

下面是 Exceptional 类的完整代码。它有一个相当大的 API,它是 Optional API 的纯扩展,因此它可以在任何现有代码中替代它——除了它不是最终 的子类型code>可选类。该类可以看作与 Try 具有相同的关系。 monad as OptionalMaybe monad 一起使用:它从中汲取灵感,但适应了 Java 习语(例如实际抛出异常,甚至来自非终端操作) .

这些是类(class)遵循的一些关键准则:

  • 与一元方法相反,它不会忽略 Java 的异常机制;

  • 反而缓解了异常与高阶函数之间的阻抗不匹配;

  • 异常处理不是静态类型安全的(由于偷偷抛出),但在运行时始终是安全的(除非明确请求,否则永远不会吞下异常)。

该类试图涵盖处理异常的所有典型方法:

  • recover 使用一些提供替代值的处理代码;
  • flatRecover,类似于 flatMap,允许返回一个新的 Exceptional 实例,该实例将被解包并适本地返回当前实例的状态已更新;
  • propagate 一个异常,将其从 Exceptional 表达式中抛出,并使 propagate 调用声明此异常类型;
  • propagate 包装到另一个异常后(翻译 it);
  • handle它,导致一个空的Exceptional;
  • 作为处理的一种特殊情况,吞下它用一个空的处理程序 block 。

propagate 方法允许人们有选择地选择他想从他的代码中公开哪些检查异常。在调用终端操作(如 get)时仍未处理的异常将在不声明的情况下偷偷地抛出。这通常被认为是一种先进且危险的方法,但通常被用作一种在某种程度上减轻检查异常与未声明它们的 lambda 形状相结合的滋扰的方法。 Exceptional 类希望为偷偷摸摸的 throw 提供一种更清洁、更有选择性的替代方案。


/*
* Copyright (c) 2015, Marko Topolnik. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class Exceptional<T>
{
private final T value;
private final Throwable exception;

private Exceptional(T value, Throwable exc) {
this.value = value;
this.exception = exc;
}

public static <T> Exceptional<T> empty() {
return new Exceptional<>(null, null);
}

public static <T> Exceptional<T> ofNullable(T value) {
return value != null ? of(value) : empty();
}

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

public static <T> Exceptional<T> ofNullableException(Throwable exception) {
return exception != null? new Exceptional<>(null, exception) : empty();
}

public static <T> Exceptional<T> ofException(Throwable exception) {
return new Exceptional<>(null, Objects.requireNonNull(exception));
}

public static <T> Exceptional<T> from(TrySupplier<T> supplier) {
try {
return ofNullable(supplier.tryGet());
} catch (Throwable t) {
return new Exceptional<>(null, t);
}
}

public static Exceptional<Void> fromVoid(TryRunnable task) {
try {
task.run();
return new Exceptional<>(null, null);
} catch (Throwable t) {
return new Exceptional<>(null, t);
}
}

public static <E extends Throwable> Consumer<? super E> swallow() {
return e -> {};
}

public T get() {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
throw new NoSuchElementException("No value present");
}

public T orElse(T other) {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
return other;
}

public T orElseGet(Supplier<? extends T> other) {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
return other.get();
}

public Stream<T> stream() {
return value == null ? Stream.empty() : Stream.of(value);
}

public<U> Exceptional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (value == null) return new Exceptional<>(null, exception);
final U u;
try {
u = mapper.apply(value);
} catch (Throwable exc) {
return new Exceptional<>(null, exc);
}
return ofNullable(u);
}

public<U> Exceptional<U> flatMap(Function<? super T, Exceptional<U>> mapper) {
Objects.requireNonNull(mapper);
return value != null ? Objects.requireNonNull(mapper.apply(value)) : empty();
}

public Exceptional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (value == null) return this;
final boolean b;
try {
b = predicate.test(value);
} catch (Throwable t) {
return ofException(t);
}
return b ? this : empty();
}

public <X extends Throwable> Exceptional<T> recover(
Class<? extends X> excType, Function<? super X, T> mapper)
{
Objects.requireNonNull(mapper);
return excType.isInstance(exception) ? ofNullable(mapper.apply(excType.cast(exception))) : this;
}

public <X extends Throwable> Exceptional<T> recover(
Iterable<Class<? extends X>> excTypes, Function<? super X, T> mapper)
{
Objects.requireNonNull(mapper);
for (Class<? extends X> excType : excTypes)
if (excType.isInstance(exception))
return ofNullable(mapper.apply(excType.cast(exception)));
return this;
}

public <X extends Throwable> Exceptional<T> flatRecover(
Class<? extends X> excType, Function<? super X, Exceptional<T>> mapper)
{
Objects.requireNonNull(mapper);
return excType.isInstance(exception) ? Objects.requireNonNull(mapper.apply(excType.cast(exception))) : this;
}

public <X extends Throwable> Exceptional<T> flatRecover(
Iterable<Class<? extends X>> excTypes, Function<? super X, Exceptional<T>> mapper)
{
Objects.requireNonNull(mapper);
for (Class<? extends X> c : excTypes)
if (c.isInstance(exception))
return Objects.requireNonNull(mapper.apply(c.cast(exception)));
return this;
}

public <E extends Throwable> Exceptional<T> propagate(Class<E> excType) throws E {
if (excType.isInstance(exception))
throw excType.cast(exception);
return this;
}

public <E extends Throwable> Exceptional<T> propagate(Iterable<Class<? extends E>> excTypes) throws E {
for (Class<? extends E> excType : excTypes)
if (excType.isInstance(exception))
throw excType.cast(exception);
return this;
}

public <E extends Throwable, F extends Throwable> Exceptional<T> propagate(
Class<E> excType, Function<? super E, ? extends F> translator)
throws F
{
if (excType.isInstance(exception))
throw translator.apply(excType.cast(exception));
return this;
}

public <E extends Throwable, F extends Throwable> Exceptional<T> propagate(
Iterable<Class<E>> excTypes, Function<? super E, ? extends F> translator)
throws F
{
for (Class<? extends E> excType : excTypes)
if (excType.isInstance(exception))
throw translator.apply(excType.cast(exception));
return this;
}

public <E extends Throwable> Exceptional<T> handle(Class<E> excType, Consumer<? super E> action) {
if (excType.isInstance(exception)) {
action.accept(excType.cast(exception));
return empty();
}
return this;
}

public <E extends Throwable> Exceptional<T> handle(Iterable<Class<E>> excTypes, Consumer<? super E> action) {
for (Class<? extends E> excType : excTypes)
if (excType.isInstance(exception)) {
action.accept(excType.cast(exception));
return empty();
}
return this;
}

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) return value;
if (exception != null) sneakyThrow(exception);
throw exceptionSupplier.get();
}

public boolean isPresent() {
return value != null;
}

public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
if (exception != null) sneakyThrow(exception);
}

public boolean isException() {
return exception != null;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
return obj instanceof Exceptional && Objects.equals(value, ((Exceptional)obj).value);
}

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

@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
}

@FunctionalInterface
public interface TrySupplier<T> {
T tryGet() throws Throwable;
}

@FunctionalInterface
public interface TryRunnable {
void run() throws Throwable;
}

关于java - 以功能方式处理异常的更好方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31270759/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com