Java 8 Lambda函数抛出异常?

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

Function<String, Integer>

然而,如果函数抛出异常,比如它被定义为:

Integer myMethod(String s) throws IOException

我该如何定义这个引用呢?

455717 次浏览

免责声明:我还没有使用过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
    public interface CheckedFunction<T, R> {
    R apply(T t) throws IOException;
    }
    

    并使用它:

    void foo (CheckedFunction f) { ... }
    
  • Otherwise, wrap Integer myMethod(String s) in a method that doesn't declare a checked exception:

    public Integer myWrappedMethod(String s) {
    try {
    return myMethod(s);
    }
    catch(IOException e) {
    throw new UncheckedIOException(e);
    }
    }
    

    然后:

    Function<String, Integer> f = (String t) -> myWrappedMethod(t);
    

    或者:

    Function<String, Integer> f =
    (String t) -> {
    try {
    return myMethod(t);
    }
    catch(IOException e) {
    throw new UncheckedIOException(e);
    }
    };
    

这并不是Java 8所特有的。你正在尝试编译一些等价的东西:

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

使用Function包装器的另一种解决方案是返回结果包装器的实例,如果一切正常,则返回成功,或者返回失败。

一些代码来澄清事情:

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());
我所做的是允许用户在异常情况下给出他实际想要的值。 我得到这样的东西

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)

实际上,您可以使用一个处理异常的新接口扩展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");
});

更新

看起来,榴莲中有一个非常不错的实用程序库,叫做错误,可以用来更灵活地解决这个问题。例如,在上面的实现中,我明确地定义了错误处理策略(System.out...throw RuntimeException),而Durian的Errors允许您通过一套实用程序方法动态应用策略。感谢分享它, @NedTwigg!

示例用法:

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

这个问题也一直困扰着我;这就是为什么我创建了这个项目

用它你可以做:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK总共定义了39个接口,它们都有Throwing等量齐点;这些都是在流中使用的# eyz1(基础的Stream,还有IntStreamLongStreamDoubleStream)。

当它们中的每一个都扩展了它们的非抛出对应对象时,你也可以直接在lambdas中使用它们:

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

默认行为是,当您抛出lambda抛出一个检查异常时,将抛出一个ThrownByLambdaException,并将检查异常作为原因。因此,您可以捕捉到它并得到原因。

其他特性也可用。

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();
}
}

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

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")

我认为榴莲的Errors结合了上述各种建议的许多优点。

然而,你可以创建自己的FunctionalInterface,抛出如下..

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

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

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");


}


}

你可以。

扩展@marcg的UtilException,并在必要的地方添加泛型<E extends Exception>:这样,编译器会强迫你再次添加抛出子句,一切就像你可以在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 { }
}

您可以使用。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的作者)

这里已经贴出了很多很棒的回复。只是试图用不同的角度来解决问题。这只是我的两毛钱,如果我哪里说错了,请指正。

在FunctionalInterface中抛出子句不是一个好主意

我认为强制抛出IOException可能不是一个好主意,原因如下

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

  • 此外,流中的异常处理变得非常可怕。例如,如果我使用你的API,下面是我的代码

               acceptMyMethod(s -> {
    try {
    Integer i = doSomeOperation(s);
    return i;
    } catch (IOException e) {
    // try catch block because of throws clause
    // in functional method, even though doSomeOperation
    // might not be throwing any exception at all.
    e.printStackTrace();
    }
    return null;
    });
    

    很难看,不是吗?此外,正如我在第一点中提到的,doSomeOperation方法可能会也可能不会抛出IOException(取决于客户端/调用者的实现),但由于FunctionalInterface方法中的throws子句,我总是必须编写try-catch.

如果我知道这个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;
    
    
    default Optional<Integer> myMethod(String s, Consumer<? super Exception> exceptionConsumer) {
    try {
    return Optional.ofNullable(this.myMethod(s));
    } catch (Exception e) {
    if (exceptionConsumer != null) {
    exceptionConsumer.accept(e);
    } else {
    e.printStackTrace();
    }
    }
    
    
    return Optional.empty();
    }
    }
    

    默认方法将消费者对象作为参数,它将负责处理异常。现在,从客户的角度来看,代码看起来是这样的

    strStream.map(str -> amazingAPIs.myMethod(str, Exception::printStackTrace))
    .filter(Optional::isPresent)
    .map(Optional::get).collect(toList());
    

    漂亮对吧?当然,记录器或其他处理逻辑可以用来代替Exception::printStackTrace。< / p >

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

如果你不介意使用第三方库(Vavr),你可以写

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

它也有所谓的Try单子来处理错误:

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

请阅读更多在这里

声明:我是Vavr的创造者。

如果您不介意使用第三方库,使用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");

您可以使用unthrow包装

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

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

创建一个自定义返回类型,该类型将传播已检查的异常。这是创建一个新接口的替代方案,该新接口映射现有的函数接口,只需在函数接口的方法上稍微修改一个“抛出异常”。

定义

CheckedValueSupplier

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

CheckedValue

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循环。

默认情况下,Java 8 函数不允许抛出异常,正如在多个回答中所建议的那样,有许多方法来实现它,其中一种方法是:

@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

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

更进一步,不是传递异常的类型,而是传递异常类型的Consumer,如……

Consumer<E extends Exception>

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

我会做一些一般的事情:

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());

鬼鬼祟祟的扔可以绕过Lambda表达式的CheckedException。将CheckedException包装在RuntimeException中不利于严格的错误处理。

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

下面是臂的回答的简单改进版本。

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包装在重新抛出中。它使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;
}


}

找到完整的代码和单元测试在这里

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

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

Jool Git Link

特别是在org.jooq.lambda.fi.util.function包的库查找中。它包含Java-8中所有带有前置Checked的接口。参考如下:-

enter image description here

我是一个小库的作者,它有一些通用的魔法,可以在不需要捕捉它们,也不需要将它们包装到RuntimeException的任何地方抛出任何Java异常。

< >强用法: # EYZ0 < / p >

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);
}
}
}

来源:# EYZ0

我使用一个名为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);
}
}
}

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

SneakyThrow不会静默地吞咽、包装到RuntimeException中,或以其他方式修改所列出的检查异常类型的任何异常。JVM不检查被检查异常系统的一致性;Javac可以,而且这个注释允许您选择不使用它的机制。

https://projectlombok.org/features/SneakyThrows

对我来说,首选的解决方案是使用Lombok。这是一个很好的图书馆。

而不是:

Integer myMethod(String s) throws IOException

你会有

import lombok.SneakyThrows;


@SneakyThrows
Integer myMethod(String s)

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