在Java中模拟goto

时间:2014-04-09 14:12:56

标签: java

我有代码(简化的假设示例):

public String handleEditRequest(...) {
    if (isBadArg()) {
       ...
       req.getSession().setAttribute("errorMessage", "...");
       return "redirect:/product/edit" + id + "/.htm";
    }
    if (isEntityNotInDataBase()) {
       ...
       req.getSession().setAttribute("errorMessage", "...");
       return "redirect:/error.htm";
    }
    ...
    return "redirect:/product/show" + id + "/.htm";
}

现在我有责任为此代码添加SLA计时计算。如果我只有一个return语句,我只需将方法体包装在:

public String handleEditRequest(...) {
    Timer timer = new Timer().start();
    // ... CODE ...
    slaService.send(timer.stop());
    return "redirect:/product/show" + id + "/.htm";
}

但错误处理代码阻止了这样的解决方案。有很多种可能性。例如,添加:

timer.stop();
slaService.send(timer);
在任何return声明之前

。但这会导致代码重复。

或者使用try {} catch () {}(Emacs Elisp经验给我启发):

private static class GotoError extends Throwable {}

public String handleEditRequest(...) {
    Timer timer = new Timer().start();
    String redirectUrl = "redirect:/product/show" + id + "/.htm";
    try {
        if (isBadArg()) {
           ...
           req.getSession().setAttribute("errorMessage", "...");
           redirectUrl = "redirect:/product/edit" + id + "/.htm";
           throw new GotoError();
        }
        if (isEntityNotInDataBase()) {
           ...
           req.getSession().setAttribute("errorMessage", "...");
           redirectUrl = "redirect:/error.htm";
           throw new GotoError();
        }
        ...
    } catch (GotoError e) { }
    slaService.send(timer.stop());
    return redirectUrl;
}

但是今天我重新思考并使用do { ... break; ... } while (false);范例(在谷歌上搜索我发现while (true) {if () {break} .... break;}示例,但我讨厌最后的中断声明!!):

public String handleEditRequest(...) {
    Timer timer = new Timer().start();
    String redirectUrl = "redirect:/product/show" + id + "/.htm";
    do {
        if (isBadArg()) {
           ...
           req.getSession().setAttribute("errorMessage", "...");
           redirectUrl = "redirect:/product/edit" + id + "/.htm";
           break;
        }
        if (isEntityNotInDataBase()) {
           ...
           req.getSession().setAttribute("errorMessage", "...");
           redirectUrl = "redirect:/error.htm";
           break;
        }
        ...
    } while (false);
    slaService.send(timer.stop());
    return redirectUrl;
}

在Java中的错误检查代码中使用什么构造来进行goto?我是否会错过一些自然解决问题的内置语言结构?

PS

C-like错误处理来自我在普通C中的10年,并允许使用线性代码。许多Java意大利面看起来像:

if (!bad1()) {
    if (!bad2()) {
        if (!bad3()) {
            if (!bad4()) { ... }}}}

这可以写成:

if (bad1())
   return errorCode;
if (bad2())
    throw new Ex();
if (bad3())
   return null;
if (bad4())
   break;
// Now do job, all fine!

2 个答案:

答案 0 :(得分:5)

将整个方法包装在另一个方法中:

public String handleEditRequest(...) {
    Timer timer = new Timer().start();
    try {
        return handleEditRequestImpl(...);
    } finally {
        timer.stop();
        slaService.send(timer);
    }
}

private String handleEditRequestImpl(...) {
    // Lots of code
}

如果handleEditRequest正在实现一个接口,您甚至可以使用proxy自动计时该接口中方法的所有调用。 (代理将通过以相同的方式处理每个方法来实现接口:启动计时器,调用实际方法,停止计时器。)

(如其他地方所述,看起来您可能很可能将更多的错误处理集中在一起......)

答案 1 :(得分:2)

显而易见的事情是将所有错误代码放在一个单独的函数中,并使用return来突破。您甚至可以转发状态或抛出异常。

我在Java中使用了do{...}while(false);,但这是相当不合时宜的。