javaexceptionerror-handlingexceptionhandleruncaughtexceptionhandler

How to handle Exceptions in Java


I have a script that process millions of data. Same data are corrupted, thus the framework I use is fail and throws exception. I am dependent to a framework that I cannot change/update. I have use it as it is. Every time I use function of this framework I use try/catch. Therefore, I am using lots of try/catch blocks as a result the code become unreadable I want to get rid of try/catch and handle exceptions separately from my code.

I want o have a global exception handler so whenever framework throws Exception it should catch and log and the loop that process data should be continue. There are web frameworks like spring and jersey which have a global exception handler. I want similar behaviour for script.

I tried Thread.UncaughtExceptionHandler but the default behavior of UncaughtExceptionHandler is stop the process when exception occurred so it is not worked.

Currently my code looks like this. I want to get rid of try/catch blocks.

public static void main(String[] args)  throws FrameworkException {
    List<Element> elements = new ArrayList<>(); //Millons of data
    processItems(elements)
}

public void processItems(List<Element> items) throws FrameworkException{
    for (int i = 0; i < elements.size(); i++) {
        try{
            framework.doSomething(elements.get(i));
        }
        catch(FrameworkException e){
            // handle
        }

        // . . .

        try{
            framework.doDifferentThing(elements.get(i));
        }
        catch(FrameworkException e){
            // handle
        }

        // . . .
    }

    System.out.println("Processing completed.");
}

My dream code and exceptions are handled in globally.

public void processItems(List<Element> items) throws FrameworkException{
    for (int i = 0; i < elements.size(); i++) {
            framework.doSomething(elements.get(i));

            // . . .

            framework.doDifferentThing(elements.get(i));

             // . . .
    }
    System.out.println("Processing completed.");
}

Solution

  • You could define a functional interface to represent actions performed on any Element that might throw a FrameworkException. Then, you just need to implement a method that accepts both the action and the current item. This method both encapsulates the try-catch logic and applies the action to the item.

    @FunctionalInterface
    public interface ElementAction {
      void execute(Element element) throws FrameworkException;
    }
    
    public void tryAction(ElementAction action, Element element) {
      try {
        action.execute(element);
      } catch (FrameworkException e) {
        // do whatever you usually do for exceptions
      }
    }
    

    This way you can have your processItems be cleaner like this:

    public void processItems(List<Element> items) {
      for (Element item : items) {
        tryAction(element -> framework.doSomething(item), item);
    
        // . . .
    
        tryAction(element -> framework.doDifferentThing(item), item);
    
        // . . .
        }
    
        // cont.
    }
    

    edit(just read the comments on the main post):

    You can extend the tryAction method by passing in a BiConsumer that takes in an Element and a FrameworkException for custom loggin.

    @FunctionalInterface
    public interface ExceptionLogger extends BiConsumer<Element, FrameworkException> {}
    

    You would then add it to the tryAction method:

    public void tryAction(ElementAction action, Element element, ExceptionLogger logger) {
      try {
        action.execute(element);
      } catch (FrameworkException e) {
        logger.accept(element, e);
      }
    }
    

    Then in your processItems you would add your way of logging the exception:

    public void processItems(List<Element> items) {
      for (Element item : items) {
        tryAction((
          element -> framework.doSomething(item), 
          item,
          (element, e) -> System.err.println("this error " + e.getMessage())
        );
    
        // . . .
    
        tryAction(
          element -> framework.doDifferentThing(item),
          item,
          (element, e) -> System.err.println("that error " + e.getMessage())
        );
    
        // . . .
        }
    
        // cont.
    }
    

    (this is assuming you are using Java 8+, which you really should be these days)