1
votes

I have been given the task of reducing try-catch blocks in my Java code for increasing performance. But each try block is checking for a entirely different kind of exception and that too custom exceptions. How to reduce the try-catch blocks.

The sample of a part of my code is as follows:-

        // Get a test engine and use that to initialize and save the test
        // taker
        TestEngine testEngine = null;
        try {
            testEngine = objFactory.getTestEngine(login.getTestengine());
        } catch (NoTestEngineException e) {
            // Add an error message, then throw the exception to struts to
            // handle
            request.setAttribute("errmsg", "Cannot create test engine: " + login.getTestengine());
            request.setAttribute("errcause", "exception.notestengine.cause");

            throw e;
        }

        //added for null check of variable testEngine
                if(testEngine==null)
                {
                    request.setAttribute("errmsg", "Could not obtain a testengine");
                }

        // Do we need to save the session id?
        String saveSessionId = objFactory.getConfigValue("testengine." + login.getTestengine() + ".recordjessionid", "false");
        String sessionId = null;
        if (saveSessionId.trim().equals("true")) {
            sessionId = request.getSession().getId();
        }



        Testtaker testTaker = null;
        try {
            testTaker = testEngine.buildTestTaker(login, null, sessionId, null, null);
        } catch (Exception e) {
            request.getSession().removeAttribute(ConstantLibrary.SESSION_LOGIN);

            CaslsUtils.outputLoggingData(log_, request);

            // Add an error message, then throw the exception to struts to
            // handle
            request.setAttribute("errmsg", "Cannot build a test taker.");
            request.setAttribute("errcause", "exception.testtakerbuildfailed.cause");

            //throw new NoTestTakerException("Failed to build testtaker.");
            throw e;
        }
5
you can add several catch blocks to one single try block. since Java 7, you can also catch several types of Exceptions within one single catch block: catch(ExceptionA | ExceptionB | ExceptionC e){} catch(Exception ex){}Stultuske
Try/Catch blocks don't have a performance impact (well, they do, but it's beyond tiny) unless the catch block gets entered. Have you measured how often the catch block is getting executed?Dave
I usually hate comments like this one, but... are you sure that reducing the number of try-catch blocks is going to help performance? They're very cheap unless an exception is actually thrown. And if exceptions are thrown that often, chances are you're using exceptions to handle expected logic flow, rather than exceptional cases -- which is not what they were intended for.yshavit
If an end user gets a description of the problem, what can they do with that? I would just place a try/catch around all the code and look at the exception type and the line number.Peter Lawrey
Most of your exception in the catch block are re-throwing the exception back, which I would refrain from doing. As commented above, you should only throw an exception in exceptional cases and catching the exception means, you are recovering from the exception.Ashish

5 Answers

2
votes

If your exception type is different for each block in that case you can join your try block to one and add multiple catch block to a with single try block

try {
    TestEngine testEngine = objFactory.getTestEngine(login.getTestengine());

    //added for null check of variable testEngine
    if(testEngine==null) {
        request.setAttribute("errmsg", "Could not obtain a testengine");
    }

    // Do we need to save the session id?
    String saveSessionId = objFactory.getConfigValue("testengine." + login.getTestengine() + ".recordjessionid", "false");
    String sessionId = null;
    if (saveSessionId.trim().equals("true")) {
        sessionId = request.getSession().getId();
    }

    Testtaker testTaker = testEngine.buildTestTaker(login, null, sessionId, null, null);
} catch (NoTestEngineException e) {
    // Add an error message, then throw the exception to struts to
    // handle
    request.setAttribute("errmsg", "Cannot create test engine: " + login.getTestengine());
    request.setAttribute("errcause", "exception.notestengine.cause");

    throw e;
} catch (Exception e) {
    request.getSession().removeAttribute(ConstantLibrary.SESSION_LOGIN);

    CaslsUtils.outputLoggingData(log_, request);

    // Add an error message, then throw the exception to struts to
    // handle
    request.setAttribute("errmsg", "Cannot build a test taker.");
    request.setAttribute("errcause", "exception.testtakerbuildfailed.cause");

    //throw new NoTestTakerException("Failed to build testtaker.");
    throw e;
}
0
votes

You can change two try-catch blocks into one:

TestEngine testEngine = null;
Testtaker testTaker = null;

try {
  testEngine = objFactory.getTestEngine(login.getTestengine()); 

  String saveSessionId = 
    objFactory.getConfigValue("testengine." + login.getTestengine() + ".recordjessionid", "false");

  String sessionId = saveSessionId.trim().equals("true") ? 
    request.getSession().getId() : null;

  testTaker = testEngine.buildTestTaker(login, null, sessionId, null, null);
}
catch (NoTestEngineException e) {
  // Add an error message, then throw the exception to struts to handle
  request.setAttribute("errmsg", "Cannot create test engine: " + login.getTestengine());
  request.setAttribute("errcause", "exception.notestengine.cause");

  throw e;
}
catch (Exception e) {
  request.getSession().removeAttribute(ConstantLibrary.SESSION_LOGIN);

  CaslsUtils.outputLoggingData(log_, request);

  // Add an error message, then throw the exception to struts to handle
  request.setAttribute("errmsg", "Cannot build a test taker.");
  request.setAttribute("errcause", "exception.testtakerbuildfailed.cause");

  throw e;
}
0
votes

I would write it like this

 public void someMethod(... args) throws Exception {
    // taker
    TestEngine testEngine = objFactory.getTestEngine(login.getTestengine());

    // Do we need to save the session id?
    String saveSessionId = objFactory.getConfigValue("testengine." + login.getTestengine() + ".recordjessionid", "false");
    String sessionId = null;
    if (saveSessionId.trim().equals("true")) {
        sessionId = request.getSession().getId();
    }

    Testtaker testTaker =  testEngine.buildTestTaker(login, null, sessionId, null, 
}

And I would have the caller handle any exceptions.

0
votes

Unlike C++, try-catch-finally blocks (exceptions) are essential parts of Java; they should be used and used properly. I also don't think they have significant performance effects; they will be thrown anyway even if you don't catch them (will be caught by the main thread finally). But for aesthetical reasons, you may reorganize them or use a single one for the whole method as in:

method() {
 try {
 } catch (Ex1 e1) {
 } catch (Ex2 e2) {
 } finally {
 }
}

you can also consider processing them, not throwing again and processing in every method in the call stack (this may have -a bit of?- performance impact..)..

0
votes

As the comments have noted, the number of try/catch blocks aren't the problem - it's the fact you're hitting them so often that is.

Assuming that you've analysed the performance and it is actually this method that is giving you issues, you should take the obvious steps to avoid exceptions being thrown (and the stack unwound as a result).

For example, you're not returning from the method if testEngine is null after the getTestEngine() call, but you're going to immediately get a NPE after testEngine.buildTestTaker(), hitting one of your catch blocks. Instead you should return from the method (with an appropriate error code) if testEngine is null, avoiding the stack unwind penalty.