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

Function<String, Integer>

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

Integer myMethod(String s) throws IOException

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


当前回答

这个问题也一直困扰着我;这就是我创建这个项目的原因。

用它你可以做:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK总共定义了39个接口,它们都有类似的抛出功能;这些都是流中使用的@ functionalinterface(基本流,还有IntStream, LongStream和DoubleStream)。

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

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

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

其他特性也可用。

其他回答

我在课堂上遇到了这个问题。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")

你可以。

扩展@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 { }
}

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函数不允许抛出异常,正如在多个回答中所建议的那样,有许多方法来实现它,其中一种方法是:

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

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

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

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

https://projectlombok.org/features/SneakyThrows