Reputation: 48753
I have code (simplified hypothetical example):
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";
}
Now I have task to add SLA timing calculation to this code. If I have only one return statement I just wrap method body in:
public String handleEditRequest(...) {
Timer timer = new Timer().start();
// ... CODE ...
slaService.send(timer.stop());
return "redirect:/product/show" + id + "/.htm";
}
But error handling code block such solution. There are many possibilities. For example add:
timer.stop();
slaService.send(timer);
before any return
statement. But this lead to code duplication.
Or use try {} catch () {}
(inspired to me by Emacs Elisp experience):
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;
}
But today I rethink and use do { ... break; ... } while (false);
paradigm (after googling I found while (true) {if () {break} .... break;}
example, but I hate final break statement!!):
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;
}
What construct to use for goto in error checking code in Java? Do I miss some build-in language constructs that naturally solve problem?
PS
C-like error handling come from my 10 year in plain C and allow to live with linear code. Many Java spaghetti look like:
if (!bad1()) {
if (!bad2()) {
if (!bad3()) {
if (!bad4()) { ... }}}}
when this can be written like:
if (bad1())
return errorCode;
if (bad2())
throw new Ex();
if (bad3())
return null;
if (bad4())
break;
// Now do job, all fine!
Upvotes: 1
Views: 333
Reputation: 1500385
Just wrap the whole method in another one:
public String handleEditRequest(...) {
Timer timer = new Timer().start();
try {
return handleEditRequestImpl(...);
} finally {
timer.stop();
slaService.send(timer);
}
}
private String handleEditRequestImpl(...) {
// Lots of code
}
If handleEditRequest
is implementing an interface, you could even potentially use a proxy to automatically time all invocations of methods in that interface. (The proxy would implement the interface by handling each method the same way: start timer, invoke the real method, stop timer.)
(As noted elsewhere, it looks like you could quite possibly centralize more of your error handling too...)
Upvotes: 5
Reputation: 234685
The obvious thing to do is to put all your error code in a separate function and use return
to break out. You can even relay a status or throw an exception.
I use do{...}while(false);
in Java a fair bit but it is rather anachronistic.
Upvotes: 2