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

Function<String, Integer>

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

Integer myMethod(String s) throws IOException

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


当前回答

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

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

其他回答

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

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

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

默认情况下,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;
};

并在调用者方法中添加抛出或尝试/捕获相同的异常。

如果你不介意使用第三方自由库(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的创造者。

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