try catch块创建干净代码的最佳实践是什么?

时间:2011-04-12 09:13:03

标签: java exception-handling

  

可能重复:
  Best practices for exception management in JAVA or C#

我今天早些时候在stackoverflow上阅读了a question,这让我想到了处理异常的最佳做法。

所以,我的问题是处理产生干净和高质量代码的例外的最佳做法

这是我的代码,我认为它很安静,但如果我错了或不清楚,请告诉我! 我试图在方法中牢记可测试性和相同的抽象级别。

欢迎每一条建设性意见。 :)

import java.awt.Point;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

/**
 * <p>This is a dummy code.</p>
 * The aim is present the best practice on exception separation and handling.
 */
public class ExceptionHandlingDemo {
    // System.out is not a good practice. Using logger is good for testing too (can be checked if the expected error messages are produced).
    private Logger logger = LoggerFactory.getLogger(ExceptionHandlingDemo.class);

    // instance of cannot work with List<Point>
    private interface PointList extends List<Point> {}

    /**
     * The method that loads a list of points from a file.
     * @param path - The path and the name of the file to be loaded.
     * Precondition: path cannot be {@code null}. In such case {@link NullPointerException} will be thrown. 
     * Postcondition: if the file don't exist, some IOException occurs or the file doesn't contain the list the returned object is {@code null}.
     * */
    /* (Google throws NullpointerExceptio) since it is not forbidden for the developers to throw it. I know this is arguable but this is out of topic for now. */
    public List<Point> loadPointList(final String path) {
        Preconditions.checkNotNull(path, "The path of the file cannot be null");

        List<Point> pointListToReturn = null;
        ObjectInputStream in = null;

        try {
            in = openObjectInputStream(path);
            pointListToReturn = readPointList(in);
        } catch (final Throwable throwable) {
            handleException(throwable);
        } finally {
            close(in);
        }

        return pointListToReturn;
    }

    /*======== Private helper methods by now ========*/

    private ObjectInputStream openObjectInputStream(final String filename) throws FileNotFoundException, IOException {
        return new ObjectInputStream(new FileInputStream(filename));
    }

    private List<Point> readPointList(final ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
        final Object object = objectInputStream.readObject();

        List<Point> ret = null;

        if (object instanceof PointList) {
            ret = (PointList) object;
        }
        return ret;
    }

    private void handleException(final Throwable throwable) {
        // I don't know the best practice here ...
        logger.error(throwable.toString());
    }

    private void close(final Closeable closeable) { 
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                logger.error("Failed closing: %s", closeable);
            }
        }
    }

    /*======== Getters and setters by now. ========*/

    // ...

    /**
     * @param args
     */
    public static void main(String[] args) {
        ExceptionHandlingDemo test = new ExceptionHandlingDemo();
        test.loadPointList("test-filename.ext");
    }
}

编辑:

我想避免的是在彼此之后写下大量的捕获案例......

4 个答案:

答案 0 :(得分:5)

乍一看有些建议:

  1. 您不应该抓住Throwable而是尽可能地捕获异常的特定。捕获Throwable的问题在于包括ErrorOutOfMemoryError类。你想让它们通过(出于某种原因,它们是未经检查的)。
  2. 当您记录异常时总是传递异常,而不仅仅是toString()。没有堆栈跟踪就很难诊断问题。
  3. 您可能不需要一般的异常处理方法。
  4. 因此,在您捕获异常的地方,您需要这样的东西:

    } catch (IOException e) {
        logger.error("some relevant message", e);
        // now handle the exception case
    }
    

    如果可能,该消息应包含一些上下文信息。当有人在搜索日志时,任何可能有助于追踪问题的内容。

答案 1 :(得分:2)

对于我不打扰的检查异常,我总是使用org.apache.commons.lang.UnhandledException。

例如

/**
 * Calls Thread.sleep(millis)
 */
public static void threadSleep(final long millis) {
    try {
        Thread.sleep(millis);
    } catch (final InterruptedException e) {
        throw new UnhandledException(e);
    }
}

答案 2 :(得分:1)

始终抓住可能的最具体的异常 - 否则永远不会抓住扔掉。

对我来说最重要的是你永远不会有一个空的catch块 - 其中一个可能需要花费大量的时间才能找到try中的某些内容是否会引发异常。

我个人希望尽快删除已检查的例外情况,并在可能的情况下将其替换为前/后条件检查。与未经检查的异常相同 - 但是未经检查的异常实际上是指示程序员错误的相当好的方式,如参数检查以确保对象状态(虽然断言可能更好)

答案 3 :(得分:0)

您可以选择一些选项。

  1. 使用异常的最重要的一个优点是,您可以拥有所有案例的唯一异常处理程序。编写代码时,首先要考虑功能,然后再考虑异常处理。因此,您可以在某些地方跳过try / catch以查看未经检查的异常,并将方法声明为throws SomeCheckedException以查看已检查的异常。这允许您拥有最少数量的异常处理程序。

  2. 如果您不知道究竟如何处理异常,只需重新抛出即可。

  3. 如果您捕获已检查的异常,但您不希望使用您的代码的客户端必须处理异常,则可以将异常更新检查为未选中。 (Hibernate通过这种方式处理异常。它们捕获已检查的sql异常并抛出未经检查的异常,而不是这个)
  4. 如果以前的建议对您不方便,那么您也可以选择一些选项:
    • 您可以添加日志记录并重新抛出相同的异常
    • 您可以通过使用initCause()方法抛出新异常来使用异常链
    • 您可能认为调用代码的代码不应该知道有关原始异常的任何信息,您可以通过创建新异常或使用fillInStackTrace()方法对其进行归档。
  5. 关于抓住Throwable。是的,你不应该抓住它的方法。但通常情况下,使用您的程序的客户端根本不需要查看异常,因此,您可能会在链中的顶级异常处理程序中捕获Throwable。