Java 8 Java 8 lambda捕获异常
Cay Horstmann的《不耐烦的人的爪哇8》一书中: 你不是一直都很讨厌你要处理的事情吗 Runnable中的异常?编写一个方法Java 8 Java 8 lambda捕获异常,java-8,unchecked-exception,Java 8,Unchecked Exception,Cay Horstmann的《不耐烦的人的爪哇8》一书中: 你不是一直都很讨厌你要处理的事情吗 Runnable中的异常?编写一个方法取消选中,以捕获所有 检查异常并将其转换为未检查的异常。对于 例如 new Thread(uncheck( () -> { System.out.println("Zzz"); Thread.sleep(1000); })).start(); // Look, no catch (InterruptedException)! 提示:定义一个接口Runnab
取消选中
,以捕获所有
检查异常并将其转换为未检查的异常。对于
例如
new Thread(uncheck(
() -> { System.out.println("Zzz"); Thread.sleep(1000); })).start();
// Look, no catch (InterruptedException)!
提示:定义一个接口RunnableEx
,其run
方法可以抛出任何
例外情况。然后实施
public static Runnable uncheck(RunnableEx runner)
在uncheck函数中使用lambda表达式
我的代码如下:
public interface RunnableEx {
void run() throws Exception;
}
public class TestUncheck {
public static Runnable uncheck(RunnableEx r) {
return new Runnable() {
@Override
public void run() {
try {
r.run();
} catch (Exception e) {
}
}
};
}
public static void main(String[] args) {
new Thread(uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
)).start();
}
}
我是按照暗示做的吗?有更好的方法吗
还有一个补充问题:
为什么不能使用Callable
而不是RunnableEx?
这种从lambdas捕获异常的方法工作得很好,并且(添加了一些内容)是在流行的Java库中的
Unchecked
类中实现的
要进行比较,请参阅它们的静态方法,该方法与您的解决方案相同,只是它们的异常处理程序和lambda省略了返回值
关于从Java 8到不耐烦者的赋值,您的uncheck
方法不使用lambda(为此,请参阅Unchecked.runnable
方法),并且不会引发未检查的异常。为此,您的catch
块(当前为空)需要将异常包装为未检查的异常。有很多方法可以做到这一点,很多问题都与此相关:
但一个简单的方法是:
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
最后,为了回答Callable
问题,我假设您的意思是“而不是Runnable
”?如果是这样,那是因为中的构造函数将Runnable
作为参数。您的代码无法将选中的异常包装为未选中的异常。此外,它不遵循使用lambda表达式的提示。更正后的版本为:
public static Runnable uncheck(RunnableEx r) {
return () -> {
try {
r.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
确实有可能进一步改进这一点。由于RunnableEx
接口的全部目的是包装Runnable
,因此可以将工厂方法放在接口本身中:
public interface RunnableEx {
void run() throws Exception;
public static Runnable uncheck(RunnableEx r) {
return () -> {
try {
r.run();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
当然,现在您的呼叫代码必须适应:
public static void main(String[] args) {
new Thread(RunnableEx.uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
)).start();
}
现在,接口本身可以实现包装功能,与Runnable
兼容,这将消除使用Runnable
和RunnableEx
实例来表示单个操作的需要:
public interface RunnableEx extends Runnable {
void runWithException() throws Exception;
@Override default void run() {
try {
runWithException();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Runnable uncheck(RunnableEx r) {
return r;
}
}
请注意,虽然调用代码在语法上没有改变,但它首先会隐式地创建一个runnablex
实例,当创建RunnableEx
实例时,这就是为什么取消选中
成为不可操作的原因,仅作为应创建RunnableEx
而不是Runnable
的标记。使用此接口定义,您可以通过
public static void main(String[] args) {
new Thread( (RunnableEx) () -> {
System.out.println("Zzz");
Thread.sleep(1000);
}
).start();
}
这里不能“仅使用”一个可调用的Callable
的原因是Callable
仍然是一个Callable
,需要实现代码返回一个值。换句话说,没有从void
到void
的隐式转换。因此可以使用它,但是lambda表达式需要返回null代码>语句结尾处(null
是唯一与Void
兼容的值)
公共类测试取消选中{
publicstaticrunnable取消选中(callabler){
返回()->{
试试{r.call();}
catch(异常e){抛出新的RuntimeException(e);}
};
}
公共静态void main(字符串[]args){
新线程(取消选中(
() -> {
System.out.println(“Zzz”);
睡眠(1000);
返回null;
}
)).start();
}
}
public class TestUncheck {
public static Runnable uncheck(Callable<Void> r) {
return () -> {
try { r.call(); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
public static void main(String[] args) {
new Thread(uncheck(
() -> {
System.out.println("Zzz");
Thread.sleep(1000);
return null;
}
)).start();
}
}