我有一个方法可以执行一些超时任务。我使用ExecutorServer.submit()获取Future对象,然后使用超时调用future.get()。这工作正常,但是我的问题是处理可能由我的任务引发的检查异常的最佳方法。以下代码可以正常工作,并保留检查的异常,但是如果方法签名中的检查的异常列表发生更改,则显得非常笨拙且容易中断。
对于如何解决这个问题,有任何的建议吗?我需要以Java 5为目标,但我也想知道在Java的较新版本中是否有好的解决方案。
public static byte[] doSomethingWithTimeout( int timeout ) throws ProcessExecutionException, InterruptedException, IOException, TimeoutException {
Callable<byte[]> callable = new Callable<byte[]>() {
public byte[] call() throws IOException, InterruptedException, ProcessExecutionException {
//Do some work that could throw one of these exceptions
return null;
}
};
try {
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Future<byte[]> future = service.submit( callable );
return future.get( timeout, TimeUnit.MILLISECONDS );
} finally {
service.shutdown();
}
} catch( Throwable t ) { //Exception handling of nested exceptions is painfully clumsy in Java
if( t instanceof ExecutionException ) {
t = t.getCause();
}
if( t instanceof ProcessExecutionException ) {
throw (ProcessExecutionException)t;
} else if( t instanceof InterruptedException ) {
throw (InterruptedException)t;
} else if( t instanceof IOException ) {
throw (IOException)t;
} else if( t instanceof TimeoutException ) {
throw (TimeoutException)t;
} else if( t instanceof Error ) {
throw (Error)t;
} else if( t instanceof RuntimeException) {
throw (RuntimeException)t;
} else {
throw new RuntimeException( t );
}
}
}
===更新===
许多人发布的响应建议要么1)作为一般例外重新抛出,或者2)作为未经检查的例外重新抛出。我不想做任何一个,因为这些异常类型(ProcessExecutionException,InterruptedException,IOException,TimeoutException)很重要-
所处理的调用将分别处理它们。如果我不需要超时功能,那么我希望我的方法抛出这4种特定的异常类型(好吧,除了TimeoutException)。我认为添加超时功能不应更改我的方法签名以抛出通用的Exception类型。
我已经深入研究了这个问题,很混乱。在Java
5、6或7中没有简单的答案。除了您指出的笨拙,冗长和脆弱之外,您的解决方案实际上还存在一个问题,ExecutionException
即您在调用时要剥离的代码getCause()
实际上包含了大多数内容。重要的堆栈跟踪信息!
也就是说,在您提供的代码中执行该方法的线程的所有堆栈信息仅在ExcecutionException中,而不在嵌套原因中,而嵌套原因仅覆盖call()
Callable中的帧。也就是说,您的doSomethingWithTimeout
方法甚至不会出现在您抛出的异常的堆栈跟踪中!您只会从执行程序中获得无实体的堆栈。这是因为ExecutionException
是唯一在调用线程上创建的(请参阅FutureTask.get()
)。
我知道的唯一解决方案很复杂。很多问题起源与自由派异常规范的Callable
- throws Exception
。您可以定义新的变体,Callable
其中的新变体可以精确地指定它们引发的异常,例如:
public interface Callable1<T,X extends Exception> extends Callable<T> {
@Override
T call() throws X;
}
这使执行可调用对象的方法具有更精确的throws
子句。如果要支持最多N个异常的签名,很遗憾,您将需要此接口的N个变体。
现在,您可以围绕JDK编写包装,该包装Executor
采用增强的Callable并返回增强的功能Future
,例如番石榴的CheckedFuture。被检查的异常类型在编译时从的创建和类型传播ExecutorService
到返回的Future
s,并最终getChecked
在将来使用该方法。
这就是您通过编译时类型安全性的方式。这意味着,而不是调用:
Future.get() throws InterruptedException, ExecutionException;
您可以致电:
CheckedFuture.getChecked() throws InterruptedException, ProcessExecutionException, IOException
因此避免了展开问题-您的方法立即引发所需类型的异常,并且这些异常在编译时可用并进行了检查。
在内部getChecked
,但是您 仍然
需要解决上述“遗漏原因”展开问题。您可以通过将(调用线程的)当前堆栈缝合到引发的异常的堆栈上来实现此目的。这扩展了Java中堆栈跟踪的通常用法,因为单个堆栈跨线程扩展,但是一旦知道发生了什么,它就会起作用并且很容易理解。
另一种选择是创建 另一个
同样的事情作为一个被抛出的异常,并设定原为新的事业。您将获得完整的堆栈跟踪,并且原因关系将与它的工作方式相同ExecutionException
-但您将拥有正确的异常类型。但是,您将需要使用反射,并且不能保证它能正常工作,例如,对于没有构造函数的具有常规参数的对象。
我有一个超时执行任务的方法。我使用ExecutorServer.submit()获取一个Future对象,然后调用future.get()并超时。这很好,但是我的问题是处理我的任务可能抛出的检查异常的最好方法。下面的代码工作正常,并且保留了被检查的异常,但是如果方法签名中被检查的异常的列表改变了,它看起来非常笨拙并且容易出错。 关于如何解决这个问题的任何建议?我需要以Java 5为目标,但我也很好
因此,我有一个Javascript脚本,它在一个循环中将小的分数相加,它有可能将0.2加到0.1。然后,这个值被输入到另一个函数,但问题是,我需要0.3来精确输入,而不是0.3000000000000004。 什么是最简单的方法,以确保数字是正确和准确的。注意,它可能得到0.25+0.125等,被添加到简单的四舍五入到小数点1不会解决问题。 也有可能添加0.2+0.1000000000000000
问题内容: 我经常遇到以下情况,其中我需要提供许多不同类型的权限。我主要在SQL Server 2000中使用ASP.NET/VB.NET。 设想 我想提供一个可以在不同参数上工作的动态权限系统。假设我想授予部门或特定人员访问应用程序的权限。并假装我们拥有不断增长的应用程序。 过去,我选择了我知道的以下两种方法之一。 将单个许可权表与特殊列一起使用,这些特殊列用于确定如何应用参数。此示例中的特殊列
上周,我决定尝试Perl6,并开始重新实现我的一个程序。我不得不说,Perl6对于对象编程来说非常容易,这对我来说是Perl5非常痛苦的一个方面。 我的程序必须读取和存储大文件,如整个基因组(高达3 Gb或更多,见下面的例子1)或制表数据。 代码的第一个版本是通过逐行迭代以Perl5的方式制作的(“基因组.fa”。对于正确的执行时间,它非常慢且不可行。 所以经过一点RTFM之后,我改变了文件上的s
问题内容: 每次我需要使用Java中的日期和/或时标时,我总是觉得自己做错了事,花了无尽的时间试图找到使用API的更好方法,而不必编写自己的Date and Time实用程序类。这是我刚遇到的一些烦人的事情: 从0开始的月份。我意识到最佳实践是使用Calendar.SEPTEMBER而不是8,但是令人讨厌的是8代表9月而不是8月。 获取没有时间戳的日期。我一直需要将日期的时间戳部分清零的实用程
问题内容: 我有一个针对客户的减速器,另一个针对AppToolbar的减速器,还有一些其他的减速器… 现在让我们说我创建了一个删除客户端的提取操作,如果失败,我在Clients reducer中会有代码,该代码应该做一些事情,但是我也想在AppToolbar中显示一些全局错误。 但是客户端和AppToolbar减速器不共享状态的同一部分,因此我无法在减速器中创建新的动作。 那么我应该如何显示全局错