ChatGPT解决这个技术问题 Extra ChatGPT

抛出异常的Java 8 Lambda函数?

我知道如何创建对具有 String 参数并返回 int 的方法的引用,它是:

Function<String, Integer>

但是,如果函数抛出异常,这将不起作用,例如定义为:

Integer myMethod(String s) throws IOException

我将如何定义这个参考?

所有的解决方案看起来都像是抛出运行时异常,我相信这不是一个好的解决方案。所以最好使用旧的 java for 循环
jool 库呢? cf org.jooq.lambda.Unchecked 包

S
Simeon Leyzerzon

您需要执行以下操作之一。

如果是你的代码,那么定义你自己的声明检查异常的函数接口:@FunctionalInterface public interface CheckedFunction { R apply(T t) throws IOException;并使用它: void foo (CheckedFunction f) { ... }

否则,将 Integer myMethod(String s) 包装在未声明已检查异常的方法中: public Integer myWrappedMethod(String s) { try { return myMethod(s); } catch(IOException e) { throw new UncheckedIOException(e); } } 然后: Function f = (String t) -> myWrappedMethod(t);或: Function f = (String t) -> { try { return myMethod(t); } catch(IOException e) { throw new UncheckedIOException(e); } };


如果您使用默认方法,您实际上可以扩展 ConsumerFunction - 请参阅下面的答案。
我认为这可以作为one-liner来完成。
次要优化:也可以使用方法引用 this::myWrappedMethod 代替 (String t) -> myWrappedMethod(t)
一种更通用的方法是像这样定义检查函数 @FunctionalInterface public interface CheckedFunction { R apply(T t) throws E;通过这种方式,您还可以定义函数抛出的异常,并且可以将接口重用于任何代码。
从 C# 到 Java 的感觉就像是全身心投入。
C
Cœur

实际上,您可以使用处理异常的新接口扩展 Consumer(和 Function 等)——使用 Java 8 的默认方法

考虑这个接口(扩展 Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

然后,例如,如果您有一个列表:

final List<String> list = Arrays.asList("A", "B", "C");

如果您想通过一些引发异常的代码来使用它(例如,使用 forEach),您通常会设置一个 try/catch 块:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

但是有了这个新接口,你可以用 lambda 表达式实例化它,编译器不会报错:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

或者甚至只是让它更简洁!:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

更新:看起来 Durian 中有一个非常不错的实用程序库部分,称为 Errors,它可用于解决这个问题,并且更加灵活。例如,在我上面的实现中,我明确定义了错误处理策略(System.out...throw RuntimeException),而 Durian 的错误允许您通过大量实用程序方法动态应用策略。感谢 sharing it,@NedTwigg!。

示例用法:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));

所以你有一组接口(Function、Consumer、Supplier...)和一组处理错误的策略(Throwing、System.out.println...)。我认为 there's a way 可以轻松使用具有任何功能的任何策略,而无需复制粘贴“ThrowingConsumer、ThrowingFunction 等”。
一段时间后......我决定使用未经检查的异常,而不使用任何额外的功能接口或新库 -> 简单的道路,更少的输入,更快的交付,不是吗。
这是 an improved version 使用偷偷摸摸的投掷习语。无需将 RuntimeException 解包到 CheckException 中。
我更喜欢这种方法,而不是使用库或其他东西。还是非常感谢。
C
Community

我认为 Durian's Errors class 结合了上述各种建议的许多优点。

将抛出函数包装到标准 Java 8 函数接口。

轻松指定处理错误的各种策略

在包装返回值的方法时,指定默认值或重新抛出 RuntimeException 之间存在重要区别。

抛出 Java 8 的功能接口版本类似于 fge 的答案

类似于 fge 的回答

用于抛出特定异常的标准接口解决了 Zoltán 的问题

这解决了佐尔坦的担忧

要将 Durian 包含在您的项目中,您可以:

从 com.diffplug.durian:durian:3.3.0 的 jcenter 或 maven Central 获取它

或者只是将两个小类复制粘贴到您的代码中:Throwing.java 和 Errors.java


或者您可以只使用 RxJava,因为流需要固有的错误处理,并且如果您的管道中存在引发异常的东西,则很有可能它可能是一个可观察的流。这也不会强制库的下游消费者使用 Java 8。
请注意,自 2016 年 6 月以来,Durian 没有新版本。这不是一个噱头,但需要牢记。
榴莲维护者在这里。什么坏了?如果用户发现错误或重要的缺失功能,我们会迅速发布错误修复。该库很简单,因此我们没有任何错误报告,因此我们不需要发布任何错误修复。
请记住,目前,您需要复制的不仅仅是“两个小班”。
a
assylias

这不是 Java 8 特有的。您正在尝试编译等效于:

interface I {
    void m();
}
class C implements I {
    public void m() throws Exception {} //can't compile
}

问题是“我将如何定义这个引用?”。这实际上并不能回答问题。它只是澄清了问题所在。
A
Adam R. Nelson

免责声明:我还没有使用过 Java 8,只是读过它。

Function<String, Integer> 不会抛出 IOException,因此您不能在其中放入任何 throws IOException 代码。如果您正在调用一个需要 Function<String, Integer> 的方法,那么您传递给该方法的 lambda 不能抛出 IOException,句号。您可以像这样编写 lambda(我认为这是 lambda 语法,不确定):

(String s) -> {
    try {
        return myMethod(s);
    } catch (IOException ex) {
        throw new RuntimeException(ex);
        // (Or do something else with it...)
    }
}

或者,如果您将 lambda 传递给的方法是您自己编写的,您可以定义一个新的函数式接口并将其用作参数类型而不是 Function<String, Integer>

public interface FunctionThatThrowsIOException<I, O> {
    O apply(I input) throws IOException;
}

在您的界面之前添加 @FunctionalInterface 注释,只有这样它才能用于 lambdas。
@Gangnus:不需要 @FunctionalInterface 注释即可用于 lambda。建议进行完整性检查。
n
nob

如果您不介意使用第 3 方库 (Vavr),您可以编写

CheckedFunction1<String, Integer> f = this::myMethod;

它还具有处理错误的所谓 Try monad:

Try(() -> f.apply("test")) // results in a Success(Integer) or Failure(Throwable)
        .map(i -> ...) // only executed on Success
        ...

请阅读更多here

免责声明:我是 Vavr 的创造者。


J
JohnnyO

但是,您可以创建自己的 FunctionalInterface,如下所示。

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

然后使用 Lambda 或引用实现它,如下所示。

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}

S
SeregaLBN

您可以使用 unthrow wrapper

Function<String, Integer> func1 = s -> Unthrow.wrap(() -> myMethod(s));

或者

Function<String, Integer> func2 = s1 -> Unthrow.wrap((s2) -> myMethod(s2), s1);

N
Neuron

Sneaky throw idiom 启用绕过 Lambda 表达式的 CheckedException。将 CheckedException 包装在 RuntimeException 中不利于严格的错误处理。

它可以用作 Java 集合中使用的 Consumer 函数。

这是 jib's answer 的简单改进版本。

import static Throwing.rethrow;

@Test
public void testRethrow() {
    thrown.expect(IOException.class);
    thrown.expectMessage("i=3");

    Arrays.asList(1, 2, 3).forEach(rethrow(e -> {
        int i = e.intValue();
        if (i == 3) {
            throw new IOException("i=" + i);
        }
    }));
}

这只是将 lambda 包装在 rethrow 中。它使 CheckedException 重新抛出任何在您的 lambda 中抛出的 Exception

public final class Throwing {
    private Throwing() {}

    @Nonnull
    public static <T> Consumer<T> rethrow(@Nonnull final ThrowingConsumer<T> consumer) {
        return consumer;
    }

    /**
     * The compiler sees the signature with the throws T inferred to a RuntimeException type, so it
     * allows the unchecked exception to propagate.
     * 
     * http://www.baeldung.com/java-sneaky-throws
     */
    @SuppressWarnings("unchecked")
    @Nonnull
    public static <E extends Throwable> void sneakyThrow(@Nonnull Throwable ex) throws E {
        throw (E) ex;
    }

}

查找完整的代码和单元测试here


P
PaoloC

你可以。

扩展 @marcg 的 UtilException 并在必要时添加通用 <E extends Exception>:这样,编译器将再次强制您添加 throw 子句,一切就好像您可以在 java 8 的流上本地抛出已检查异常一样。

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

public class LambdaExceptionUtilTest {

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    private static class MyTestException extends Exception { }
}

S
Sergio

我在 lambda 中遇到了 Class.forName 和 Class.newInstance 这个问题,所以我做了:

public Object uncheckedNewInstanceForName (String name) {

    try {
        return Class.forName(name).newInstance();
    }
    catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

在 lambda 内部,我没有调用 Class.forName("myClass").newInstance() 我只是调用了 uncheckedNewInstanceForName ("myClass")


j
justin.hughey

创建将传播检查的异常的自定义返回类型。这是创建一个镜像现有功能接口的新接口的替代方法,只需对功能接口的方法上的“抛出异常”稍作修改。

定义

CheckedValue 供应商

public static interface CheckedValueSupplier<V> {
    public V get () throws Exception;
}

检查值

public class CheckedValue<V> {
    private final V v;
    private final Optional<Exception> opt;

    public Value (V v) {
        this.v = v;
    }

    public Value (Exception e) {
        this.opt = Optional.of(e);
    }

    public V get () throws Exception {
        if (opt.isPresent()) {
            throw opt.get();
        }
        return v;
    }

    public Optional<Exception> getException () {
        return opt;
    }

    public static <T> CheckedValue<T> returns (T t) {
        return new CheckedValue<T>(t);
    }

    public static <T> CheckedValue<T> rethrows (Exception e) {
        return new CheckedValue<T>(e);
    }

    public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            return Result.rethrows(e);
        }
    }

    public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
        try {
            return CheckedValue.returns(sup.get());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

用法

//  Don't use this pattern with FileReader, it's meant to be an
//  example.  FileReader is a Closeable resource and as such should
//  be managed in a try-with-resources block or in another safe
//  manner that will make sure it is closed properly.

//  This will not compile as the FileReader constructor throws
//  an IOException.
    Function<String, FileReader> sToFr =
        (fn) -> new FileReader(Paths.get(fn).toFile());

// Alternative, this will compile.
    Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
        return CheckedValue.from (
            () -> new FileReader(Paths.get("/home/" + f).toFile()));
    };

// Single record usage
    // The call to get() will propagate the checked exception if it exists.
    FileReader readMe = pToFr.apply("/home/README").get();


// List of records usage
    List<String> paths = ...; //a list of paths to files
    Collection<CheckedValue<FileReader>> frs =
        paths.stream().map(pToFr).collect(Collectors.toList());

// Find out if creation of a file reader failed.
    boolean anyErrors = frs.stream()
        .filter(f -> f.getException().isPresent())
        .findAny().isPresent();

这是怎么回事?

创建了一个引发检查异常的单一功能接口 (CheckedValueSupplier)。这将是唯一允许检查异常的功能接口。所有其他功能接口都将利用 CheckedValueSupplier 包装任何引发检查异常的代码。

CheckedValue 类将保存执行任何引发检查异常的逻辑的结果。这可以防止已检查异常的传播,直到代码尝试访问 CheckedValue 实例包含的值为止。

这种方法的问题。

我们现在抛出“异常”,有效地隐藏了最初抛出的特定类型。

在调用 CheckedValue#get() 之前,我们不知道发生了异常。

消费者等

某些功能接口(例如 Consumer)必须以不同的方式处理,因为它们不提供返回值。

代替消费者的功能

一种方法是使用函数而不是消费者,这适用于处理流。

    List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
    .map(e -> CheckedValueSupplier.from(
        () -> {throwyMethod(e); return e;}))
    .filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior

升级

或者,您可以随时升级到 RuntimeException。还有其他答案涵盖了从 Consumer 中升级检查的异常。

不要消费。

只需避免一起使用功能接口并使用老式的 for 循环即可。


y
yohan

使用函数包装器的另一个解决方案是返回结果包装器的一个实例,比如成功,如果一切顺利,或者返回一个实例,比如失败。

一些代码来澄清事情:

public interface ThrowableFunction<A, B> {
    B apply(A a) throws Exception;
}

public abstract class Try<A> {

    public static boolean isSuccess(Try tryy) {
        return tryy instanceof Success;
    }

    public static <A, B> Function<A, Try<B>> tryOf(ThrowableFunction<A, B> function) {
        return a -> {
            try {
                B result = function.apply(a);
                return new Success<B>(result);
            } catch (Exception e) {
                return new Failure<>(e);
            }
        };
    }

    public abstract boolean isSuccess();

    public boolean isError() {
        return !isSuccess();
    }

    public abstract A getResult();

    public abstract Exception getError();
}

public class Success<A> extends Try<A> {

    private final A result;

    public Success(A result) {
        this.result = result;
    }

    @Override
    public boolean isSuccess() {
        return true;
    }

    @Override
    public A getResult() {
        return result;
    }

    @Override
    public Exception getError() {
        return new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object that) {
        if(!(that instanceof Success)) {
            return false;
        }
        return Objects.equal(result, ((Success) that).getResult());
    }
}

public class Failure<A> extends Try<A> {

    private final Exception exception;

    public Failure(Exception exception) {
        this.exception = exception;
    }

    @Override
    public boolean isSuccess() {
        return false;
    }

    @Override
    public A getResult() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Exception getError() {
        return exception;
    }
}

一个简单的用例:

List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
    map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
    collect(Collectors.toList());

f
fge

这个问题也一直困扰着我;这就是我创建 this project 的原因。

有了它,您可以:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK 定义了总共 39 个接口,它们具有这样的 Throwing 等价物;这些都是在流中使用的 @FunctionalInterface(基本 Stream,还有 IntStreamLongStreamDoubleStream)。

由于它们每个都扩展了它们的非抛出对应物,您也可以直接在 lambdas 中使用它们:

myStringStream.map(f) // <-- works

默认行为是,当您抛出的 lambda 抛出已检查的异常时,会以已检查的异常为原因抛出 ThrownByLambdaException。因此,您可以捕捉到这一点并找出原因。

其他功能也可用。


我真的很喜欢这个想法,我只希望您按照此处的建议将 throwable 设为通用:javaspecialists.eu/archive/Issue221.html,例如:@FunctionalInterface public interface SupplierWithCE<T, X extends Exception> { T get() throws X; } - 这样用户就不需要捕获 Throwable,而是需要捕获特定的已检查异常。
@Zoltán 每次都声明异常会很痛苦;此外,您始终可以只使用 .apply() 而不是 .doApply() 并捕获 ThrownByLambdaException,您会将原始异常作为原因(或者您可以使用 rethrow(...).as(MyRuntimeException.class)
我认为有(某种)a way around this
@NedTwigg 我早就解决了这个问题;我现在可以使用 Throwing.runnable() 和其他工具,始终具有链接功能
链接功能非常酷!我的评论是关于 ThrowingRunnable 是否应该具有通用异常。 Zoltan 询问您的库是否可以将参数作为通用参数,您说使用起来会很痛苦。我的链接是一些代码行,这些代码行显示了一种使异常通用的方法,而不是痛苦。除非我误读了它,否则您的库中的异常不是通用的(这是一个合理的设计选择,因为将它们设为通用并不会获得太多实用性)。
T
TriCore

这里已经发布了很多很棒的回复。只是试图从不同的角度解决问题。这只是我的 2 美分,如果我在某个地方错了,请纠正我。

在功能接口中抛出子句不是一个好主意

我认为这可能不是一个好主意,因为以下原因强制 throws IOException

这在我看来像是 Stream/Lambda 的反模式。整个想法是调用者将决定提供什么代码以及如何处理异常。在许多情况下,IOException 可能不适用于客户端。例如,如果客户端从缓存/内存中获取价值,而不是执行实际的 I/O。

此外,流中的异常处理变得非常可怕。例如,如果我使用您的 API acceptMyMethod(s -> { try { Integer i = doSomeOperation(s); return i; } catch (IOException e) { // try catch 块,因为 throws 子句,下面是我的代码// 在函数式方法中,即使 doSomeOperation // 可能根本不会抛出任何异常。 e.printStackTrace(); } return null; });是不是很丑?此外,正如我在第一点中提到的,doSomeOperation 方法可能会或可能不会抛出 IOException(取决于客户端/调用者的实现),但由于您的 FunctionalInterface 方法中的 throws 子句,我总是必须编写试着抓。

如果我真的知道这个 API 会抛出 IOException,我该怎么办

那么可能我们将 FunctionalInterface 与典型的接口混淆了。如果你知道这个 API 会抛出 IOException,那么你很可能也知道一些默认/抽象行为。我认为您应该定义一个接口并部署您的库(使用默认/抽象实现),如下所示 public interface MyAmazingAPI { Integer myMethod(String s) throws IOException;但是,客户端的 try-catch 问题仍然存在。如果我在流中使用你的 API,我仍然需要在可怕的 try-catch 块中处理 IOException。

提供一个默认的流友好 API 如下 public interface MyAmazingAPI { Integer myMethod(String s) throws IOException;默认 Optional myMethod(String s, Consumer exceptionConsumer) { try { return Optional.ofNullable(this.myMethod(s)); } catch (Exception e) { if (exceptionConsumer != null) { exceptionConsumer.accept(e); } 其他 { e.printStackTrace(); } } 返回 Optional.empty();默认方法以消费者对象为参数,负责处理异常。现在,从客户端的角度来看,代码看起来像这样 strStream.map(str -> AmazingAPIs.myMethod(str, Exception::printStackTrace)) .filter(Optional::isPresent) .map(Optional::get)。收集(到列表());不错吧?当然,可以使用记录器或其他处理逻辑来代替 Exception::printStackTrace。

您还可以公开类似于 https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#exceptionally-java.util.function.Function- 的方法。这意味着您可以公开另一个方法,该方法将包含先前方法调用的异常。缺点是你现在让你的 API 有状态,这意味着你需要处理线程安全,这最终会成为性能问题。只是一个可以考虑的选择。


我同意将已检查的异常转换为未检查的异常或吞下异常不是一个好主意,因为无法知道 Stream 的哪个元素引发了异常。因此,我喜欢拥有一个异常处理程序并过滤无效结果的想法。请注意,您的 MyAmazingAPI 实际上是一个 FunctionalInterface(因此您可以添加 @FunctionalInterface 注释)。您也可以使用默认值而不是使用 Optional.empty()
A
Arpit Aggarwal

默认情况下,Java 8 Function 不允许抛出异常,正如多个答案中所建议的,有很多方法可以实现它,一种方法是:

@FunctionalInterface
public interface FunctionWithException<T, R, E extends Exception> {
    R apply(T t) throws E;
}

定义为:

private FunctionWithException<String, Integer, IOException> myMethod = (str) -> {
    if ("abc".equals(str)) {
        throw new IOException();
    }
  return 1;
};

并在调用者方法中添加 throwstry/catch 相同的异常。


S
Stephen Paul

我使用一个名为 unchecked() 的重载实用程序函数来处理多个用例。

一些示例用法

unchecked(() -> new File("hello.txt").createNewFile());

boolean fileWasCreated = unchecked(() -> new File("hello.txt").createNewFile());

myFiles.forEach(unchecked(file -> new File(file.path).createNewFile()));

支持实用程序

public class UncheckedUtils {

    @FunctionalInterface
    public interface ThrowingConsumer<T> {
        void accept(T t) throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingSupplier<T> {
        T get() throws Exception;
    }

    @FunctionalInterface
    public interface ThrowingRunnable {
        void run() throws Exception;
    }

    public static <T> Consumer<T> unchecked(
            ThrowingConsumer<T> throwingConsumer
    ) {
        return i -> {
            try {
                throwingConsumer.accept(i);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        };
    }

    public static <T> T unchecked(
            ThrowingSupplier<T> throwingSupplier
    ) {
        try {
            return throwingSupplier.get();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static void unchecked(
            ThrowingRunnable throwing
    ) {
        try {
            throwing.run();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

C
Community

为此,您可以使用 ET。 ET 是一个用于异常转换/翻译的小型 Java 8 库。

使用 ET,它看起来像这样:

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslator 实例是线程安全的,可以由多个组件共享。您可以根据需要配置更具体的异常转换规则(例如 FooCheckedException -> BarRuntimeException)。如果没有其他可用规则,检查的异常会自动转换为 RuntimeException

(免责声明:我是 ET 的作者)


看起来你是这个库的作者。根据 SO rules,您必须在回答中披露您的从属关系。请明确添加您编写此库的答案(其他与 ET 相关的答案相同)。
嗨塔吉尔,感谢您的提示。我更新了答案。
J
John McClean

如果您不介意使用第三方库,通过我贡献的库 cyclops-react,您可以使用 FluentFunctions API 编写

 Function<String, Integer> standardFn = FluentFunctions.ofChecked(this::myMethod);

ofChecked 采用 jOOλ CheckedFunction 并将软化后的引用返回到标准(未检查)JDK java.util.function.Function。

或者,您可以通过 FluentFunctions api 继续使用捕获的函数!

例如,要执行您的方法,最多重试 5 次并记录您可以编写的状态

  FluentFunctions.ofChecked(this::myMethod)
                 .log(s->log.debug(s),e->log.error(e,e.getMessage())
                 .try(5,1000)
                 .apply("my param");

m
mmounirou

我正在做的是允许用户在出现异常时给出他实际想要的值。所以我有一些看起来像这样的东西

public static <T, R> Function<? super T, ? extends R> defaultIfThrows(FunctionThatThrows<? super T, ? extends R> delegate, R defaultValue) {
    return x -> {
        try {
            return delegate.apply(x);
        } catch (Throwable throwable) {
            return defaultValue;
        }
    };
}

@FunctionalInterface
public interface FunctionThatThrows<T, R> {
    R apply(T t) throws Throwable;
}

然后可以这样调用:

defaultIfThrows(child -> child.getID(), null)

This 是这个想法的扩展,它区分了“默认值”策略(如您的答案)和“重新抛出 RuntimeException”策略,其中不需要默认值。
V
Vinay Prajapati

使用 Jool Library 或从 JOOQ 说出 jOOλ library。它不仅提供了未经检查的异常处理接口,还为 Seq 类提供了许多有用的方法。

此外,它还包含多达 16 个参数的功能接口。此外,它提供了用于不同场景的 Tuple 类。

Jool Git Link

特别是在 org.jooq.lambda.fi.util.function 包的库查找中。它包含来自 Java-8 的所有接口,前面带有 Checked。请参阅下文以供参考:-

https://i.stack.imgur.com/q3XPw.png


这是一篇博文,展示了 jOOλ 中的工作原理示例:blog.jooq.org/…
l
lbenedetto

如果你有 lombok,你可以用 @SneakyThrows 注释你的方法

SneakyThrow 不会默默吞下、包装到 RuntimeException 或以其他方式修改列出的已检查异常类型的任何异常。 JVM 不检查受检异常系统的一致性; javac 确实如此,并且此注释使您可以选择退出其机制。

https://projectlombok.org/features/SneakyThrows


惊人。我爱它。它允许您在不使用 throws 声明的情况下抛出已检查的异常。当您将函数传递给 Lambda 时非常有用。 baeldung.com/java-sneaky-throws
R
Rodney P. Barbati

一些提供的解决方案使用 E 的通用参数来传递抛出异常的类型。

更进一步,而不是传入异常类型,而是传入异常类型的消费者,如...

Consumer<E extends Exception>

您可以创建几个可重用的 Consumer<Exception> 变体,它们将满足您的应用程序的常见异常处理需求。


a
ahll

我会做一些通用的事情:

public interface Lambda {

    @FunctionalInterface
    public interface CheckedFunction<T> {

        T get() throws Exception;
    }

    public static <T> T handle(CheckedFunction<T> supplier) {
        try {
            return supplier.get();
        } catch (Exception exception) {
            throw new RuntimeException(exception);

        }
    }
}

用法:

 Lambda.handle(() -> method());

q
qoomon

我是一个小型库的作者,它具有一些通用魔法,可以在任何地方抛出任何 Java 异常,而无需捕获它们或将它们包装到 RuntimeException 中。

用法: unchecked(() -> methodThrowingCheckedException())

public class UncheckedExceptions {

    /**
     * throws {@code exception} as unchecked exception, without wrapping exception.
     *
     * @return will never return anything, return type is set to {@code exception} only to be able to write <code>throw unchecked(exception)</code>
     * @throws T {@code exception} as unchecked exception
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T unchecked(Exception exception) throws T {
        throw (T) exception;
    }


    @FunctionalInterface
    public interface UncheckedFunction<R> {
        R call() throws Exception;
    }

    /**
     * Executes given function,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @return result of function
     * @see #unchecked(Exception)
     */
    public static <R> R unchecked(UncheckedFunction<R> function) {
        try {
            return function.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }


    @FunctionalInterface
    public interface UncheckedMethod {
        void call() throws Exception;
    }

    /**
     * Executes given method,
     * catches and rethrows checked exceptions as unchecked exceptions, without wrapping exception.
     *
     * @see #unchecked(Exception)
     */
    public static void unchecked(UncheckedMethod method) {
        try {
            method.call();
        } catch (Exception e) {
            throw unchecked(e);
        }
    }
}

来源:https://github.com/qoomon/unchecked-exceptions-java


S
Stephan Zehnder

对我来说,首选的解决方案是使用 Lombok。无论如何,这是一个不错的图书馆。

代替:

Integer myMethod(String s) throws IOException

你将会有

import lombok.SneakyThrows;

@SneakyThrows
Integer myMethod(String s)

仍然会抛出异常,但您不需要使用 throws 声明它。


J
Jamal
public void frankTest() {
    int pageId= -1;

    List<Book> users= null;
    try {
        //Does Not Compile:  Object page=DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> new Portal(rw.getInt("id"), "", users.parallelStream().filter(uu -> uu.getVbid() == rw.getString("user_id")).findFirst().get(), rw.getString("name")));

        //Compiles:
        Object page= DatabaseConnection.getSpringConnection().queryForObject("SELECT * FROM bookmark_page", (rw, n) -> { 
            try {
                final Book bk= users.stream().filter(bp -> { 
                    String name= null;
                    try {
                        name = rw.getString("name");
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    return bp.getTitle().equals(name); 
                }).limit(1).collect(Collectors.toList()).get(0);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return new Portal(rw.getInt("id"), "", users.get(0), rw.getString("name")); 
        } );
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

介意评论你的作品吗?仅代码的答案不是那么有用。
@Franky,您可以通过使用 4 个间距而不是 <code>/<code> 来修复您的演示文稿 :)