从 Java ExecutorService 捕获并抛出自定义异常
Catch and throw custom Exception from Java ExecutorService
我有一个函数可以遍历 HappyObjects 列表并异步设置它们的字段。在 Callable 中,可能会发生 JsonProcessingException。我必须将此函数的这个异常和其他异常包装到一个自定义异常 (ControllerException) 中并抛出它。
Other Stack Overflow posts seem to suggest collect into a List of Futures and use get() to catch the exceptions. 因此,这是我目前所拥有的:
default List<HappyObj> fillfunction(final List<HappyObj> happyObjs) throws ControllerException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
List<Future<HappyObj>> futures = new ArrayList<>();
for (HappyObj happyObj : happyObjs) {
Future<HappyObj> future = executor.submit(
() -> {
final List<Mood> moods = getMoods();
for (Mood mood : moods) {
final String json = getJsonEmotion();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
List<Emotion> emotions =
mapper.readValue(json, new TypeReference<List<Emotion>>() {}); //JsonProcessingException can occur here
MoodMetadata metadata = mood.getMoodMetadata();
if (metadata != null && metadata.getEmotionMetadata() != null) {
metadata.getEmotionMetadata().setEmotions(emotions);
}
}
happyObj.setMoods(moods);
return happyObj;
});
futures.add(future);
}
executor.shutdown();
final long maxSlaSec = 1;
try {
executor.awaitTermination(maxSlaSec, TimeUnit.SECONDS);
List<HappyObj> happyResult = new ArrayList<>();
for (Future<HappyObj> future : futures) {
happyResult.add(future.get());
}
return happyResult;
} catch (InterruptedException | ExecutionException e) {
executor.shutdownNow();
throw new ControllerException(e);
}
}
有没有比遍历 List<Future>
并在每个上调用 get 来捕获 ExecutorException 更优雅的方法?我考虑过使用 execute() vs. submit(),但后来我无法处理 JsonProcessingException。我看到另一个 post 建议创建一个 ThreadPoolExecutor 子类并覆盖 afterExecute(),但我无法处理 JsonProcessingException。
我问这个问题的原因之一是因为这个方法主要由setter组成,所以函数最初是操作给定的对象并返回void。
根据 the docs of ExecutionException
(and also the docs of Future#get
),它已经包装了该信息。也就是说,您可以使用它的 getCause
来检查 Callable
的 body.
抛出的 Exception
注意 Callable#call
本身会抛出一个 Exception
... 当你从 Callable
抛出一个 Exception
时,它会被包装成一个 ExecutionException
] 将从 Future#get
方法中抛出, 对于每个 Callable
,这意味着您可以更改循环以捕获 ExecutionException
对于每个 Future
并检查其 getCause
!
所以您实际上不需要将其包装成自定义 ControllerException
。
您创建的 Callable
仍然可以 return null
类型 Void
例如,无需对其进行任何操作。
除非情况发生变化,否则在这种情况下不需要扩展ThreadPoolExecutor
。您甚至不必强制转换为 ThreadPoolExecutor
,因为 ExecutorService
接口已经具有您需要的 submit
。当 Callable
出现问题时,只需从 Callable
中抛出任何你需要的 Exception
(例如你提到的 JsonProcessingException
),然后检查 ExecutionException
从每个 Future#get
方法判断是否抛出 JsonProcessingException
(如果需要,您还可以在 中确定抛出哪个 )。
Is there a more elegant way than iterating through List and calling get on each to catch ExecutorException?
在我看来,不,没有,因为你想先提交所有Callable
,然后让他们运行并行,最后检查他们的ExecutionException
对于 Callable
s' body 抛出的任何 Exception
对于每个 Callable
(通过 returned Future
的 Future#get
通过 submit
).
我有一个函数可以遍历 HappyObjects 列表并异步设置它们的字段。在 Callable 中,可能会发生 JsonProcessingException。我必须将此函数的这个异常和其他异常包装到一个自定义异常 (ControllerException) 中并抛出它。
Other Stack Overflow posts seem to suggest collect into a List of Futures and use get() to catch the exceptions. 因此,这是我目前所拥有的:
default List<HappyObj> fillfunction(final List<HappyObj> happyObjs) throws ControllerException {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
List<Future<HappyObj>> futures = new ArrayList<>();
for (HappyObj happyObj : happyObjs) {
Future<HappyObj> future = executor.submit(
() -> {
final List<Mood> moods = getMoods();
for (Mood mood : moods) {
final String json = getJsonEmotion();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
List<Emotion> emotions =
mapper.readValue(json, new TypeReference<List<Emotion>>() {}); //JsonProcessingException can occur here
MoodMetadata metadata = mood.getMoodMetadata();
if (metadata != null && metadata.getEmotionMetadata() != null) {
metadata.getEmotionMetadata().setEmotions(emotions);
}
}
happyObj.setMoods(moods);
return happyObj;
});
futures.add(future);
}
executor.shutdown();
final long maxSlaSec = 1;
try {
executor.awaitTermination(maxSlaSec, TimeUnit.SECONDS);
List<HappyObj> happyResult = new ArrayList<>();
for (Future<HappyObj> future : futures) {
happyResult.add(future.get());
}
return happyResult;
} catch (InterruptedException | ExecutionException e) {
executor.shutdownNow();
throw new ControllerException(e);
}
}
有没有比遍历 List<Future>
并在每个上调用 get 来捕获 ExecutorException 更优雅的方法?我考虑过使用 execute() vs. submit(),但后来我无法处理 JsonProcessingException。我看到另一个 post 建议创建一个 ThreadPoolExecutor 子类并覆盖 afterExecute(),但我无法处理 JsonProcessingException。
我问这个问题的原因之一是因为这个方法主要由setter组成,所以函数最初是操作给定的对象并返回void。
根据 the docs of ExecutionException
(and also the docs of Future#get
),它已经包装了该信息。也就是说,您可以使用它的 getCause
来检查 Callable
的 body.
Exception
注意 Callable#call
本身会抛出一个 Exception
... 当你从 Callable
抛出一个 Exception
时,它会被包装成一个 ExecutionException
] 将从 Future#get
方法中抛出, 对于每个 Callable
,这意味着您可以更改循环以捕获 ExecutionException
对于每个 Future
并检查其 getCause
!
所以您实际上不需要将其包装成自定义 ControllerException
。
您创建的 Callable
仍然可以 return null
类型 Void
例如,无需对其进行任何操作。
除非情况发生变化,否则在这种情况下不需要扩展ThreadPoolExecutor
。您甚至不必强制转换为 ThreadPoolExecutor
,因为 ExecutorService
接口已经具有您需要的 submit
。当 Callable
出现问题时,只需从 Callable
中抛出任何你需要的 Exception
(例如你提到的 JsonProcessingException
),然后检查 ExecutionException
从每个 Future#get
方法判断是否抛出 JsonProcessingException
(如果需要,您还可以在 中确定抛出哪个 )。
Is there a more elegant way than iterating through List and calling get on each to catch ExecutorException?
在我看来,不,没有,因为你想先提交所有Callable
,然后让他们运行并行,最后检查他们的ExecutionException
对于 Callable
s' body 抛出的任何 Exception
对于每个 Callable
(通过 returned Future
的 Future#get
通过 submit
).