Java 保理试捕

Java 保理试捕,java,Java,我有一个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 (Unaut

我有一个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环境,请参阅,处理这段代码是专门为其设计的,非常简单

如果没有:

您可以让一个函数接口接受一个函数,该函数可以抛出异常并返回一个
响应

@FunctionalInterface
public interface Responder {
    Response handleRequest() throws 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
    });
}

当然,这是可能的。我们的解决方案如下所示:

    } catch (Exception exception) {
        exceptionConverter.convertAndThrow(exception);
    }
根据捕获的异常统一异常的重新抛出

因此,异常转换器是我们“切换”异常类型并执行需要执行的操作的一个中心位置。当然,这里的中心元素是:所有类都需要对传入异常进行完全相同的处理

我们甚至更进一步,允许各种潜在的“输入原因”,但我们还进行了广泛的单元测试,以确保转换总是产生预期的结果


请注意:我的答案只是重构那些“捕获”级联。您仍然可以使用TJs解决方案;但请记住:这种方法通过引入可运行特性增加了一定的复杂性。

如果所有方法都以相同的方式处理异常,则可以将异常处理提取到外部方法:

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);
    }
}

因为这是在JAX-RS上下文中进行的,所以有一种更好的方法,它不依赖于捕获许多不同的异常:使用。这是JAX-RS1.0的内置机制,它将异常类型转换为适当的
响应
对象发送给客户端

在您的情况下,可以在应用程序中定义一次以下类:

@Provider
public class UnauthorizedExceptionMapper implements ExceptionMapper<UnauthorizedException> {
   public Response toResponse(UnauthorizedException e) {
      return Response.status(401).build();
   }
}

已正确考虑异常层次结构。如果应用程序代码抛出一个
MyCustomExceptionMapper
,JAX-RS将寻找一个注册了该类型的异常映射器,如果找不到异常映射器,JAX-RS将上升到超类:这样,每隔一次就会有一个catch-all异常映射器处理一次。但对于那些不能使用Java 8的人来说,以下是如何使用早期版本的Java实现它:

响应者界面:

public interface Responder {
    Response handleRequest() throws 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表达式:

Response response = respond(new Responder() {
    @Override
    public Response handleRequest() throws Exception {
        ...
        return Response.ok().build();
    }
});

执行此操作,
catch(MyCustomerException | UnauthorizedException错误){/*异常登录以检查发生了什么*/}
否则,继续执行您正在执行的操作,因为您将根据错误类型返回错误。@Marounnaroun:当他需要注释处的不同代码时,会创建重复的异常处理代码。这些代码是否都在同一方法中调用?请尝试使用AOP ideas/tools-+1在代码中识别这一点。推荐书:罗伯特·C·马丁的《干净的代码》。就是这样解释的。单责任模式(SRP)、关注点分离(SoC)和错误处理是一个关注点。但也许有一个Java EE中间件概念可以替代,我不得不承认,我对当前Java EE的东西并不熟悉。该死,为什么我找不到一个不接受任何参数并返回
java.util.function
类?
Runnable
不是很合适,因为它不允许catch中的代码抛出任何选中的异常或返回值。我会使用自定义接口。除此之外,这个答案是我首选的解决方案,如果还没有的话,我会把它贴出来there@Dici:谢谢。只有当我在编辑添加界面时,我才意识到异常情况几乎意味着你需要自己的。我感谢大家的耐心。我现在喝第二杯咖啡。:-)如果没有Thomas Weller、NewUser、Maroun Maroun和Dici的帮助,我会用CW来回答。我会在处理程序中重新抛出异常,以在try catch中管理,而不是使用instanceof,但这没有什么区别。@AxelH抛出异常不是免费的。而且,这将是对
throw
语句的可怕滥用。如果需要
instanceof
,请使用
instanceof
@borisspider异常实例的构建不需要时间吗?基本上,
catch
的工作原理与instanceof相同,因此我想**这将花费相同的时间。因此,捕获的内容不会太详细,并且不会影响性能。这绝对是JAX-RS环境中的最佳解决方案。
public interface Responder {
    Response handleRequest() throws 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();
    }
}
Response response = respond(new Responder() {
    @Override
    public Response handleRequest() throws Exception {
        ...
        return Response.ok().build();
    }
});