我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
当前回答
实际上,您可以使用一个处理异常的新接口来扩展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)));
其他回答
我所做的是允许用户在异常情况下给出他实际想要的值。 我有一个像这样的东西
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)
免责声明:我还没有使用过Java 8,只是阅读过它。
Function<String, Integer>不抛出IOException,所以你不能在其中放入任何抛出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;
}
您需要执行以下操作之一。
If it's your code, then define your own functional interface that declares the checked exception: @FunctionalInterface public interface CheckedFunction<T, R> { R apply(T t) throws IOException; } and use it: 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); } } and then: Function<String, Integer> f = (String t) -> myWrappedMethod(t); or: 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
}
我使用一个名为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);
}
}
}