我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
我知道如何创建一个有String参数并返回int的方法的引用,它是:
Function<String, Integer>
然而,如果函数抛出异常,比如它被定义为:
Integer myMethod(String s) throws IOException
我该如何定义这个引用呢?
当前回答
我认为榴莲的错误课程结合了上面各种建议的许多优点。
将抛出函数包装到标准Java 8函数接口。 轻松指定各种处理错误的策略 在包装返回值的方法时,指定默认值和重新抛出RuntimeException之间有重要区别。 抛出Java 8的函数接口版本 类似于fge的答案 用于抛出特定异常的标准接口 这解决了Zoltán的问题
在你的项目中加入榴莲,你可以:
从jcenter或maven中心com.diffplug.durian:durian:3.3.0获取 或者只是复制粘贴两个小类到你的代码中:throws .java和Errors.java
其他回答
我认为榴莲的错误课程结合了上面各种建议的许多优点。
将抛出函数包装到标准Java 8函数接口。 轻松指定各种处理错误的策略 在包装返回值的方法时,指定默认值和重新抛出RuntimeException之间有重要区别。 抛出Java 8的函数接口版本 类似于fge的答案 用于抛出特定异常的标准接口 这解决了Zoltán的问题
在你的项目中加入榴莲,你可以:
从jcenter或maven中心com.diffplug.durian:durian:3.3.0获取 或者只是复制粘贴两个小类到你的代码中:throws .java和Errors.java
你可以。
扩展@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 { }
}
你可以使用ET。ET是一个用于异常转换/转换的小型Java 8库。
对于ET,它看起来是这样的:
// Do this once
ExceptionTranslator et = ET.newConfiguration().done();
...
// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));
// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));
ExceptionTranslator实例是线程安全的,可以由多个组件共享。如果你喜欢,你可以配置更具体的异常转换规则(例如FooCheckedException -> BarRuntimeException)。 如果没有其他可用的规则,被检查的异常将自动转换为RuntimeException。
(声明:我是ET的作者)
创建一个自定义返回类型,该类型将传播已检查的异常。这是创建一个新接口的替代方案,该新接口映射现有的函数接口,只需在函数接口的方法上稍微修改一个“抛出异常”。
定义
CheckedValueSupplier
public static interface CheckedValueSupplier<V> {
public V get () throws Exception;
}
CheckedValue
public class CheckedValue<V> {
private final V v;
private final Optional<Exception> opt;
public Value (V v) {
this.v = v;
}
public Value (Exception e) {
this.opt = Optional.of(e);
}
public V get () throws Exception {
if (opt.isPresent()) {
throw opt.get();
}
return v;
}
public Optional<Exception> getException () {
return opt;
}
public static <T> CheckedValue<T> returns (T t) {
return new CheckedValue<T>(t);
}
public static <T> CheckedValue<T> rethrows (Exception e) {
return new CheckedValue<T>(e);
}
public static <V> CheckedValue<V> from (CheckedValueSupplier<V> sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
return Result.rethrows(e);
}
}
public static <V> CheckedValue<V> escalates (CheckedValueSupplier<V> sup) {
try {
return CheckedValue.returns(sup.get());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
使用
// Don't use this pattern with FileReader, it's meant to be an
// example. FileReader is a Closeable resource and as such should
// be managed in a try-with-resources block or in another safe
// manner that will make sure it is closed properly.
// This will not compile as the FileReader constructor throws
// an IOException.
Function<String, FileReader> sToFr =
(fn) -> new FileReader(Paths.get(fn).toFile());
// Alternative, this will compile.
Function<String, CheckedValue<FileReader>> sToFr = (fn) -> {
return CheckedValue.from (
() -> new FileReader(Paths.get("/home/" + f).toFile()));
};
// Single record usage
// The call to get() will propagate the checked exception if it exists.
FileReader readMe = pToFr.apply("/home/README").get();
// List of records usage
List<String> paths = ...; //a list of paths to files
Collection<CheckedValue<FileReader>> frs =
paths.stream().map(pToFr).collect(Collectors.toList());
// Find out if creation of a file reader failed.
boolean anyErrors = frs.stream()
.filter(f -> f.getException().isPresent())
.findAny().isPresent();
这是怎么呢
创建一个抛出检查异常的功能接口(checkedvaluesprovider)。这将是唯一允许检查异常的功能接口。所有其他功能接口都将利用checkedvaluesprovider来包装抛出检查异常的任何代码。
CheckedValue类将保存抛出检查异常的任何逻辑的执行结果。这可以防止已检查异常的传播,直到代码试图访问CheckedValue实例所包含的值。
这种方法的问题。
我们现在抛出“异常”,有效地隐藏了最初抛出的特定类型。 在调用CheckedValue#get()之前,我们不知道发生了异常。
消费者等
一些功能接口(例如Consumer)必须以不同的方式处理,因为它们不提供返回值。
函数代替消费者
一种方法是使用函数而不是消费者,后者在处理流时应用。
List<String> lst = Lists.newArrayList();
// won't compile
lst.stream().forEach(e -> throwyMethod(e));
// compiles
lst.stream()
.map(e -> CheckedValueSupplier.from(
() -> {throwyMethod(e); return e;}))
.filter(v -> v.getException().isPresent()); //this example may not actually run due to lazy stream behavior
升级
或者,您总是可以升级为RuntimeException。还有其他的答案涵盖了从Consumer内部升级已检查异常。
不消费。
只需要避免所有的函数接口,并使用一个老式的for循环。
默认情况下,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;
};
并在调用者方法中添加抛出或尝试/捕获相同的异常。