关于java:CompletableFuture中的抛出异常 |
您所在的位置:网站首页 › executionexception处理 › 关于java:CompletableFuture中的抛出异常 |
我有以下代码: 123456789101112// How to throw the ServerException? public void myFunc() throws ServerException{ // Some code CompletableFuture a = CompletableFuture.supplyAsync(() -> { try { return someObj.someFunc(); } catch(ServerException ex) { // throw ex; gives an error here. } })); // Some code }someFunc()引发ServerException。我不想在这里处理此问题,但是将someFunc()的异常抛出给myFunc()的调用者。 您的代码建议您稍后以相同的方法使用异步操作的结果,因此无论如何您都必须处理CompletionException,因此处理它的一种方法是 12345678910111213141516171819202122232425public void myFunc() throws ServerException { // Some code CompletableFuture a = CompletableFuture.supplyAsync(() -> { try { return someObj.someFunc(); } catch(ServerException ex) { throw new CompletionException(ex); } }); // Some code running in parallel to someFunc() A resultOfA; try { resultOfA = a.join(); } catch(CompletionException ex) { try { throw ex.getCause(); } catch(Error|RuntimeException|ServerException possible) { throw possible; } catch(Throwable impossible) { throw new AssertionError(impossible); } } // some code using resultOfA }调用join时,在Supplier的异步处理中抛出的所有异常都将被package到CompletionException中,除了我们已经package在CompletionException中的ServerException。 重新抛出CompletionException的原因时,我们可能会遇到未检查的异常,即Error或RuntimeException的子类,或者我们的自定义检查的异常ServerException。上面的代码通过多次捕获来处理所有这些错误,然后将它们重新抛出。由于声明的getCause()返回类型为Throwable,因此尽管我们已经处理了所有可能的类型,但编译器仍要求我们处理该类型。直接的解决方案是将包裹在AssertionError中的实际上不可能的可抛出对象抛出。 或者,我们可以为自定义异常使用future的替代结果: 1234567891011121314151617181920212223public void myFunc() throws ServerException { // Some code CompletableFuture exception = new CompletableFuture(); CompletableFuture a = CompletableFuture.supplyAsync(() -> { try { return someObj.someFunc(); } catch(ServerException ex) { exception.complete(ex); throw new CompletionException(ex); } }); // Some code running in parallel to someFunc() A resultOfA; try { resultOfA = a.join(); } catch(CompletionException ex) { if(exception.isDone()) throw exception.join(); throw ex; } // some code using resultOfA }此解决方案将重新抛出所有意外结果。以package形式抛出的对象,但仅将自定义ServerException抛出为通过exception future传递的原始形式。请注意,在查询exception未来之前,必须确保a已完成(例如首先调用join()),以避免出现竞争情况。 相关讨论 非常详细的答案。 番石榴有帮助方法。捕获看起来像这样:Throwables.throwIfUnchecked(e.getCause());抛出新的RuntimeException(e.getCause()); @霍尔格出色的答案!一个需要阻塞联接以捕获并引发异步异常 @Holger:为什么不使用get()方法?那不是简单的多捕获块吗? @Miguel get与join的不同之处在于,将异常package在ExecutionException中而不是CompletionException中。这对catch端没有任何改进。它还要求调用者处理InterruptedException,这使其变得更加复杂。此外,由于Supplier不能抛出已检查的ExecutionException,因此必须保留CompletionException,然后get将提取原因并将其重新package在ExecutionException中,这样可以减少原因高效的。在特殊情况下,性能并不是很重要。但是get在这里的各个方面都比join差。对于那些寻求通过completableFuture 处理异常的其他方式的人 以下是处理解析为整数的错误的几种方法: 1。使用handle方法-使您可以提供有关异常 的默认值 1234567891011121314CompletableFuture correctHandler = CompletableFuture.supplyAsync(() ->"A") .thenApply(Integer::parseInt) .handle((result, ex) -> { if (null != ex) { ex.printStackTrace(); return 0; } else { System.out.println("HANDLING" + result); return result; } }) .thenAcceptAsync(s -> { System.out.println("CORRECT:" + s); });2。使用exceptionally方法-与handle类似,但详细程度 123456CompletableFuture parser = CompletableFuture.supplyAsync(() ->"1") .thenApply(Integer::parseInt) .exceptionally(t -> { t.printStackTrace(); return 0; }).thenAcceptAsync(s -> System.out.println("CORRECT value:" + s));3。使用whenComplete方法-使用此方法将停止该方法的执行,而不会执行下一个thenAcceptAsync 12345678910CompletableFuture correctHandler2 = CompletableFuture.supplyAsync(() ->"A") .thenApply(Integer::parseInt) .whenComplete((result, ex) -> { if (null != ex) { ex.printStackTrace(); } }) .thenAcceptAsync(s -> { System.out.println("When Complete:" + s); });4。通过completeExceptionally 传播异常 123456789public static CompletableFuture converter(String convertMe) { CompletableFuture future = new CompletableFuture(); try { future.complete(Integer.parseInt(convertMe)); } catch (Exception ex) { future.completeExceptionally(ex); } return future; } 相关讨论 对于像我这样的人,由于CompletableFuture而无法使用1、2和3,只需返回一个null即可使用Void类型的对象:)花了我几个小时来弄清楚这个简单事物。即使其他人的回答非常好。但是我给您提供了另一种在CompletableFuture中引发检查异常的方法。 如果您不想在另一个线程中调用CompletableFuture,则可以使用匿名类来处理它,如下所示: 1234567CompletableFuture a = new CompletableFuture() {{ try { complete(someObj.someFunc()); } catch (ServerException ex) { completeExceptionally(ex); } }};如果要在另一个线程中调用CompletableFuture,则还可以使用匿名类来处理它,但可以通过runAsync: 运行方法 123456789CompletableFuture a = new CompletableFuture() {{ CompletableFuture.runAsync(() -> { try { complete(someObj.someFunc()); } catch (ServerException ex) { completeExceptionally(ex); } }); }}; 相关讨论 完全不需要在匿名子类中执行此操作。子类仅浪费资源。另请参见此处和此处。 @Holger先生,谢谢。我只是在脑海里写下来。我待会再见。 @Holger先生,我发现您的两个答案不同。我更喜欢您在此问题中使用的第一个。因为它易于使用且非常清晰。我认为您应该将其package为RuntimeException并抛出: 1 throw new RuntimeException(ex);或者成为一个小实用程序会有所帮助: 123456789101112131415161718192021222324252627static class Wrapper extends RuntimeException { private Wrapper(Throwable throwable) { super(throwable); } public static Wrapper wrap(Throwable throwable) { return new Wrapper(throwable); } public Throwable unwrap() { return getCause(); } } public static void go() { CompletableFuture a = CompletableFuture.supplyAsync(() -> { try { throw new Exception("Just because"); } catch (Exception ex) { throw Wrapper.wrap(ex); } }); a.join(); }然后您可以unwrap这样。. 12345 try { go(); } catch (Wrapper w) { throw w.unwrap(); } 相关讨论 我只需要抛出一个ServerException。 @ayushgp我看不到默认流发生这种情况,因为它们不允许检查异常...也许您可以package那个而不是解包吗? 看来您的go()方法永远不会抛出任何东西。我想它缺少一个join()调用。另外,Wrapper所提供的功能不及Throwable.getCause()所提供的。我不会在不设置原因的情况下将异常package到另一个异常中,因为它违反了约定并且不会打印正确的堆栈跟踪。 @DidierL是的go只是为了证明一个观点,确实不是很有用。另一方面,Wrapper只是将检查的异常package到运行时中。 @Eugene我的意思是,在当前形式的go()中,您的try / catch永远不会真正抓住Wrapper。我觉得这很令人误解。对于Wrapper,我的意思是应该调用super(Throwable)而不是定义自己的字段,以使printStackTrace()和getCause()的行为自然符合此类package程序的预期。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |