11
\$\begingroup\$

I have the following code that checks for three different properties. Unfortunately each call can throw up to four exceptions that I all have to catch. Can I some how make the code more readable by reducing the amount of try/catch?

public void retrieveSourceCode() {
 try {
 fileName = RestServices.getInstance().getClassName(getSourceCodeURI()); 
 } catch (ClientProtocolException e) {
 fileName = "not available";
 e.printStackTrace();
 } catch (IOException e) {
 fileName = "not available";
 e.printStackTrace();
 } catch (RestServicesException e) {
 fileName = "not available";
 e.printStackTrace();
 }
 if (!(fileName.endsWith(".jar") || fileName.endsWith(".svn-base"))) {
 try {
 sourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getSourceCodeURI());
 } catch (ClientProtocolException e) {
 sourceCode = "not available";
 e.printStackTrace();
 } catch (IOException e) {
 sourceCode = "not available";
 e.printStackTrace();
 } catch (RestServicesException e) {
 sourceCode = "not available";
 e.printStackTrace();
 }
 if (before == null) {
 beforeSourceCode = "no before source code available";
 } else {
 try {
 beforeSourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getBeforeVersionURI());
 } catch (ClientProtocolException e) {
 beforeSourceCode = "no before source code available";
 e.printStackTrace();
 } catch (IOException e) {
 beforeSourceCode = "no before source code available";
 e.printStackTrace();
 } catch (RestServicesException e) {
 beforeSourceCode = "no before source code available";
 e.printStackTrace();
 }
 }
 if (after == null) {
 afterSourceCode = "no after source code available";
 } else {
 try {
 afterSourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getAfterVersionURI());
 } catch (ClientProtocolException e) {
 afterSourceCode = "no after source code available";
 e.printStackTrace();
 } catch (IOException e) {
 afterSourceCode = "no after source code available";
 e.printStackTrace();
 } catch (RestServicesException e) {
 afterSourceCode = "no after source code available";
 e.printStackTrace();
 }
 }
 }
 getChangeSet().addAffectedFile(getFileName());
 }
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jan 18, 2012 at 8:12
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Someone should of pointed out that ClientProtocolException is an IOException making catching ClientProtocolException pointless in this code. \$\endgroup\$ Commented Apr 9, 2012 at 13:44
  • \$\begingroup\$ You may not have control over it, but needing to check "before" and "after" for null is a little smelly to me. \$\endgroup\$ Commented Apr 9, 2012 at 15:31

6 Answers 6

18
\$\begingroup\$

If you upgrade to Java 7, you can use the new Multi-catch syntax. You could change the first block to:

 try {
 fileName = RestServices.getInstance().getClassName(getSourceCodeURI()); 
 } catch (ClientProtocolException | IOException | RestServicesException e) {
 fileName = "not available";
 e.printStackTrace();
 }

Essentially if there are many exceptions you catch and handle in the same way, you can use multi-catch

answered Jan 18, 2012 at 9:39
\$\endgroup\$
1
  • 3
    \$\begingroup\$ That's rather nifty. C# needs this. A lot. \$\endgroup\$ Commented Jan 23, 2012 at 17:49
12
\$\begingroup\$

These unhandled exceptions smell very bad. Storing error messages in the place of data also is not a good sign (like fileName = "not available").

Anyway, some notes:

  1. You could extract out a

    RestServices restServices = RestServices.getInstance();
    

    variable.

  2. You should create constants from repeating Strings, like "not available", "no before source code available" etc.

  3. I'd extract out getFileName method for the first try-catch block, a getSourceCode for the second, and so on.

answered Jan 18, 2012 at 10:50
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Agreed - What's the point of catching an exception if you don't deal with it? \$\endgroup\$ Commented Jan 18, 2012 at 18:42
5
\$\begingroup\$

A try and catch block should be in their own method so as not to interrupt logic in another method.

private void getClassName(T URI, String error){
 T2 className;
 try{
 className = RestServices.getInstance().getClassName(URI);
 } catch (Exception e){
 className = error;
 e.printStackTrace();
 } finally{
 return className;
 }
}

and

private void sendGetRequestJsonTextToString(T URI, String error){
 T2 reply;
 try {
 reply = RestServices.getInstance().sendGetRequestJsonTextToString(URI));
 } catch(Exception e){
 reply = error;
 e.printStackTrace();
 } finally{
 return reply;
 }
}

This method now has no try-catch block interrupting the logic. Also, guard clause can be used in place of nested ifs.

public void retrieveSourceCode(){
 String error;
 error = "not available";
 filename = getClassName(getSourceCodeURI(), error);
 // this conditional can be extracted to a method, giving more readability
 // say, if(!isSourcecode(filename))
 if(fileName.endsWith(".jar") || !fileName.endsWith(".svn-base"))){
 return;
 }
 error = "not available";
 sourceCode = sendGetRequestJsonTextToString(getSourceCodeURI(), error);
 error = "no before source code available";
 if(before == null){
 beforeSourceCode = error;
 } else {
 beforeSourceCode = sendGetRequestJsonTextToString(getBeforeVersionURI(), error);
 }
 error = "no after source code available";
 if(after == null){
 afterSourceCode = error;
 } else {
 afterSourceCode = sendGetRequestJsonTextToString(getAfterVersionURI(), error);
 }
 getChangeSet().addAffectedFile(getFileName());
}

This still has some smells (as mentioned in another answer), but it does what the questions asking for: to simplify the try-catch block.

palacsint
30.4k9 gold badges82 silver badges157 bronze badges
answered Jan 31, 2012 at 10:02
\$\endgroup\$
1
  • \$\begingroup\$ You've declared getClassName and sendGetRequestJsonTextToString as void, but then return values from them. \$\endgroup\$ Commented Apr 9, 2012 at 16:04
3
\$\begingroup\$

Considering that you do literally the exact same thing regardless of the type of exception, you can cut down the catch statements by catching type Exception instead of a specific subclass:

public void retrieveSourceCode() {
 try {
 fileName = RestServices.getInstance().getClassName(getSourceCodeURI()); 
 } catch (Exception e) {
 fileName = "not available";
 e.printStackTrace();
 }
 if (!(fileName.endsWith(".jar") || fileName.endsWith(".svn-base"))) {
 try {
 sourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getSourceCodeURI());
 } catch (Exception e) {
 sourceCode = "not available";
 e.printStackTrace();
 } 
 if (before == null) {
 beforeSourceCode = "no before source code available";
 } else {
 try {
 beforeSourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getBeforeVersionURI());
 } catch (Exception e) {
 beforeSourceCode = "no before source code available";
 e.printStackTrace();
 } 
 }
 if (after == null) {
 afterSourceCode = "no after source code available";
 } else {
 try {
 afterSourceCode = RestServices.getInstance().sendGetRequestJsonTextToString(getAfterVersionURI());
 } catch (Exception e) {
 afterSourceCode = "no after source code available";
 e.printStackTrace();
 } 
 }
 }
 getChangeSet().addAffectedFile(getFileName());
}
answered Jan 19, 2012 at 4:12
\$\endgroup\$
1
  • 2
    \$\begingroup\$ But keep in mind that this will also catch unchecked RuntimeExceptions. \$\endgroup\$ Commented Jan 31, 2012 at 11:35
1
\$\begingroup\$

Java 7 syntax wins.

For Java < 7, catching the Exception base class works but it's unfortunate to stop unrelated exceptions from propagating. Here's a workaround to consider:

String getFileName() {
 try {
 return RestServices.getInstance().getClassName(getSourceCodeURI());
 } catch (ClientProtocolException e) {
 } catch (IOException e) {
 } catch (RestServicesException) {
 }
 return "not available";
}
answered Jun 21, 2012 at 18:32
\$\endgroup\$
1
  • \$\begingroup\$ Note that you'll lose the stack trace. \$\endgroup\$ Commented Jun 22, 2012 at 14:06
0
\$\begingroup\$

You could use an if statement inside your catch. It could get ugly if you're trying to catch a lot of different exception types but it should be fine for a handful. Sorry for any errors in my syntax. It's been a while since I've used Java.

try {
 fileName = RestServices.getInstance().getClassName(getSourceCodeURI()); 
}catch (Exception e){
 if (e instanceof ClientProtocolException || e instanceof IOException || e instanceof RestServicesException) {
 fileName = "not available";
 e.printStackTrace();
 }else{
 throw e;
 }
}
answered Mar 1, 2014 at 14:18
\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Review! I'm glad you post an answer and hope you'll stay around. I'm not a big fan of this approach, this should get the job done, but is a lot of "boiler" plate IMHO. \$\endgroup\$ Commented Mar 1, 2014 at 15:35
  • \$\begingroup\$ I mostly agree, hence why I'd only use it with a small number of exceptions. Otherwise multiple catch blocks is probably the way to go, although it looks like the latest Java version has solved this problem. \$\endgroup\$ Commented Mar 1, 2014 at 16:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.