Monday, January 16, 2017

Exception handling examples

Don't swallow exceptions

Make sure the exceptions are handled and not swallowed.
    public void notifyOthers() {
        try {
            List<party> interestedParties = fetchInterestedPartiesFromDb();
        } catch (Exception e) {
            // do nothing
        }
    }

    private List<party> fetchInterestedPartiesFromDb() throws Exception {
        return fetchFromDb(Party.class);
    }

    private <t> List<t> fetchFromDb(Class<t> partyClass) {
        //interact with db
        return null;
    }

An exception caught must be logged

Make sure the complete exception is logged rather than just logging the message using Exception.getMessage().
    public void notifyOthers() {
        try {
            List<party> interestedParties = fetchInterestedPartiesFromDb();
        } catch (Exception e) {
            LOGGER.severe(e.getMessage());
        }
    }
Instead of the above, we should simply log the exception object itself so that one can see the entire execution stack.
    public void notifyOthers() {
        try {
            List<party> interestedParties = fetchInterestedPartiesFromDb();
        } catch (Exception e) {
            LOGGER.severe("Exception " + e);
        }
    }

Do not catch Throwable

If you catch Throwable even errors will be caught, for example, java.lang.OutOfMemoryError. Below code throws OutOfMemoryError but is caught instead of letting JVM deal with it. Since Throwable is superclass of Error and Exception, it will catch even those errors which indicate serious problem.

Exception hierarchy


ThrowsOom:


package refactor.clean;

import java.util.logging.Logger;

public class ThrowsOom {
    public static void main(String[] args) {
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000000; i++) {
                sb.append(i).append(sb);
            }
        } catch (Throwable t) {
            LOGGER.severe("Throwable: " + t);
        }
        LOGGER.warning("Throwable is caught, replace it with Exception");
    }

    private static final Logger LOGGER = Logger.getLogger(ThrowsOom.class.getName());
}

Output:
Jan 16, 2017 5:29:56 PM refactor.clean.ThrowsOom main
SEVERE: Throwable: java.lang.OutOfMemoryError: Java heap space
Jan 16, 2017 5:29:56 PM refactor.clean.ThrowsOom main
WARNING: Throwable is caught, replace it with Exception
Catch Exception instead of Throwable.

ThrowsOom:

package refactor.clean;

import java.util.logging.Logger;

public class ThrowsOom {
    public static void main(String[] args) {
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000000; i++) {
                sb.append(i).append(sb);
            }
        } catch (Throwable t) {
            LOGGER.severe("Throwable: " + t);
        }
        LOGGER.warning("Throwable is caught, replace it with Exception");
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 1000000; i++) {
                sb.append(i).append(sb);
            }
        } catch (Exception e) {
            LOGGER.severe("Exception: " + e);
        }
    }

    private static final Logger LOGGER = Logger.getLogger(ThrowsOom.class.getName());
}
Output:
Jan 16, 2017 5:55:11 PM refactor.clean.ThrowsOom main
SEVERE: Throwable: java.lang.OutOfMemoryError: Java heap space
Jan 16, 2017 5:55:11 PM refactor.clean.ThrowsOom main
WARNING: Throwable is caught, replace it with Exception
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.util.Arrays.copyOf(Arrays.java:3332)
 at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
 at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
 at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:445)
 at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:459)
 at java.lang.StringBuilder.append(StringBuilder.java:166)
 at refactor.clean.ThrowsOom.main(ThrowsOom.java:20)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:483)
 at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Don't throw generic exception

Below method tries to find an existing issue for the passed in ID issueId. If issue not found throws a RuntimeException.
    public static Issue findById(String issueId) throws RuntimeException {
        Issue issue = fetchFromDb(issueId);
        if (issue == null) {
            throw new RuntimeException("Issue not found");
        }
        return issue;
    }
Instead of a generic exception, one can define and throw a dedicated exception.

IssueNotFoundException:


package refactor;

public class IssueNotFoundException extends RuntimeException {
    public IssueNotFoundException(String message) {
        super(message);
    }
}
Fix findById() to throw specific exception.
    public static Issue findById(String issueId) throws IssueNotFoundException {
        Issue issue = fetchFromDb(issueId);
        if (issue == null) {
            throw new IssueNotFoundException("Issue not found");
        }
        return issue;
    }
Since the method now throws specific exception, the calling methods can handle the exception based on its type. IssueAlreadyResolvedException:

IssueAlreadyResolvedException:


package refactor;

public class IssueAlreadyResolvedException extends Exception {
    public IssueAlreadyResolvedException() {
        super("Issue already resolved");
    }
}
    public void resolve(String issueId) throws IssueAlreadyResolvedException {
        Issue issue;
        try {
             issue = Issue.findById(issueId);
        } catch (IssueNotFoundException e) {
            return;
        }
        if (issue.isResolved()) {
            throw new IssueAlreadyResolvedException();
        }
        issue.resolve();
    }

No comments:

Post a Comment