我有一个Java EE应用程序,其中有许多使用相同模式的Web服务:
public Response myWebService1() { try { // do something different depending on the web service called } catch (MyCustomException e1) { return Response.status(409).build(); } catch (UnauthorizedException e2) { return Response.status(401).build(); } catch (Exception e3) { return Response.status(500).build(); } }
这可以分解这段代码吗?
如果这是一个JAX-RS环境,请参阅Tunaki的答案,处理此问题是特别适合的并且非常简单.
如果不:
你可以有一个函数接口接受一个可以抛出异常的函数并返回一个Response
:
@FunctionalInterface public interface Responder { Response handleRequest() throws Exception; }
(正如Dici指出的那样,你可以把它变成一个通用的ThrowingSupplier
或类似的,因为你允许它扔掉Exception
.)
然后有一个辅助方法接受它的一个实例:
private static Response respond(Responder responder) { try { return responder.handleRequest(); } catch (MyCustomException e1) { return Response.status(409).build(); } catch (UnauthorizedException e2) { return Response.status(401).build(); } catch (Exception e3) { return Response.status(500).build(); } }
...并通过lambda使用它:
public Response myWebService1() { return respond(() -> { // Do stuff here, return a Response or throw / allow throws on error }); }
由于这是在JAX-RS上下文中,因此有一种更好的方法,它不依赖于捕获许多不同的异常:使用a ExceptionMapper
.这是JAX-RS 1.0的内置机制,它将异常类型转换为适当的Response
对象以发送到客户端.
在您的情况下,您可以在应用程序中定义以下类:
@Provider public class UnauthorizedExceptionMapper implements ExceptionMapper{ public Response toResponse(UnauthorizedException e) { return Response.status(401).build(); } }
@Provider public class MyCustomExceptionMapper implements ExceptionMapper{ public Response toResponse(MyCustomException e) { return Response.status(409).build(); } }
@Provider public class CatchAllExceptionMapper implements ExceptionMapper{ public Response toResponse(Exception e) { return Response.status(500).build(); } }
该@Provider
注解告诉了JAX-RS运行扫描时发现这个类.这样可以确保在代码中的任何MyCustomException
位置抛出(而不是显式捕获),将返回409响应.您的应用程序中的代码将简单地变为:
public Response myWebService1() { // do something, and don't catch anything; just care about the happy path }
正确考虑了异常层次结构.如果应用程序代码抛出一个MyCustomExceptionMapper
,JAX-RS将查找使用该类型注册的异常映射器,并且如果它找不到,那么它将上升到超类:这样,可以有一个catch-all异常映射器处理每个其他情况.
如果所有方法都以相同的方式处理异常,则可以将异常处理提取到外部方法:
public static Response exceptionHandler (Exception exc) { if (exc instanceof MyCustomException) { return Response.status(409).build(); } else if (exc instanceof UnauthorizedException) { return Response.status(401).build(); } else { return Response.status(500).build(); } } public Response myWebService1() { try { // do something different depending on the web service called } catch (Exception exc) { return exceptionHandler(exc); } }