本文翻译自:Java 8 Lambda function that throws exception?
I know how to create a reference to a method that has a String
parameter and returns an int
, it's: 我知道如何创建对具有String
参数并返回int
的方法的引用,它是:
Function<String, Integer>
However, this doesn't work if the function throws an exception, say it's defined as: 但是,如果该函数引发异常,则将其定义为:
Integer myMethod(String s) throws IOException
How would I define this reference? 我将如何定义此参考?
#1楼
参考:https://stackoom.com/question/1EMAy/抛出异常的Java-Lambda函数
#2楼
Disclaimer: I haven't used Java 8 yet, only read about it. 免责声明:我还没有使用Java 8,只阅读过它。
Function<String, Integer>
doesn't throw IOException
, so you can't put any code in it that throws IOException
. Function<String, Integer>
不会引发IOException
,因此您不能在其中放入任何throws IOException
代码。 If you're calling a method that expects a Function<String, Integer>
, then the lambda that you pass to that method can't throw IOException
, period. 如果调用的方法需要Function<String, Integer>
,则传递给该方法的lambda不能抛出IOException
,period。 You can either write a lambda like this (I think this is the lambda syntax, not sure): 您可以这样编写一个lambda(我不确定这是lambda语法):
(String s) -> {
try {
return myMethod(s);
} catch (IOException ex) {
throw new RuntimeException(ex);
// (Or do something else with it...)
}
}
Or, if the method you're passing the lambda to is one you wrote yourself, you can define a new functional interface and use that as the parameter type instead of Function<String, Integer>
: 或者,如果将lambda传递给您的方法是您自己编写的,则可以定义一个新的函数接口,并将其用作参数类型,而不是Function<String, Integer>
:
public interface FunctionThatThrowsIOException<I, O> {
O apply(I input) throws IOException;
}
#3楼
You'll need to do one of the following. 您需要执行以下操作之一。
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: 否则,将Integer myMethod(String s)
包装在未声明检查异常的方法中: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); } };
#4楼
This is not specific to Java 8. You are trying to compile something equivalent to: 这不是特定于Java 8的。您尝试编译的内容等同于:
interface I {
void m();
}
class C implements I {
public void m() throws Exception {} //can't compile
}
#5楼
Another solution using a Function wrapper would be to return either an instance of a wrapper of your result, say Success, if everything went well, either an instance of, say Failure. 使用函数包装的另一种解决方案是,如果一切顺利,则返回结果包装的一个实例,即成功;如果失败,则返回一个实例。
Some code to clarify things : 一些代码来澄清事情:
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;
}
}
A simple use case : 一个简单的用例:
List<Try<Integer>> result = Lists.newArrayList(1, 2, 3).stream().
map(Try.<Integer, Integer>tryOf(i -> someMethodThrowingAnException(i))).
collect(Collectors.toList());
#6楼
What I'm doing is to allow the user to give the value he actually want in case of exception . 我正在做的是允许用户在异常情况下提供他实际想要的值。 So I've something looking like this 所以我看起来像这样
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;
}
And this can then be call like : 然后可以这样调用:
defaultIfThrows(child -> child.getID(), null)