我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
当前回答
如果您不介意使用第三方库,使用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");
其他回答
这个问题也一直困扰着我;这就是我创建这个项目的原因。
用它你可以做:
final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;
JDK总共定义了39个接口,它们都有类似的抛出功能;这些都是流中使用的@ functionalinterface(基本流,还有IntStream, LongStream和DoubleStream)。
当它们中的每一个都扩展了它们的非抛出对应对象时,你也可以直接在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();
}
}
Sneaky throw成语允许绕过Lambda表达式的CheckedException。将CheckedException包装在RuntimeException中不利于严格的错误处理。
它可以用作Java集合中使用的Consumer函数。
下面是jib答案的一个简单改进版本。
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中抛出的任何异常。
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;
}
}
在这里找到完整的代码和单元测试。
我认为榴莲的错误课程结合了上面各种建议的许多优点。
将抛出函数包装到标准Java 8函数接口。 轻松指定各种处理错误的策略 在包装返回值的方法时,指定默认值和重新抛出RuntimeException之间有重要区别。 抛出Java 8的函数接口版本 类似于fge的答案 用于抛出特定异常的标准接口 这解决了Zoltán的问题
在你的项目中加入榴莲,你可以:
从jcenter或maven中心com.diffplug.durian:durian:3.3.0获取 或者只是复制粘贴两个小类到你的代码中:throws .java和Errors.java
实际上,您可以使用一个处理异常的新接口来扩展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");
});
更新
看起来榴莲有一个非常好的实用程序库,叫做Errors,可以用来解决这个问题,具有更大的灵活性。例如,在上面的实现中,我显式地定义了错误处理策略(System.out…或者抛出RuntimeException),而Durian的Errors允许您通过一套大型实用程序方法动态应用策略。感谢分享,@NedTwigg!
示例用法:
list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));