Java:使用try-catch,empty-try-catch,dummy-return进行错误处理

时间:2010-05-05 12:39:51

标签: java exception

searh使用递归定义的函数,可以轻松抛出异常。我已经尝试了3种处理exeptions的方法:

  1. 使用empty-try-catch()
  2. 忽略
  3. 由于exeption而导致的add-dummy-return stop err-propagation
  4. 抛出一个特定的除外。 (这部分我真的不明白。如果我扔掉除外,我可以强迫它继续在其他地方继续,而不是继续旧的除了抛出的路径吗?)
  5. 一些例外情况我不会像执行期间那样关心删除文件-exception(NullPointer),但有些例子我确实喜欢未知的东西。

    可能的例外:

        // 1. if a temp-file or some other file removed during execution -> except.
        // 2. if no permiss. -> except.
        // 3. ? --> except.
    

    整个程序的代码非常重要。我之前添加了clittered-checks,try-catches,avoid-empty-try-catchs,但它确实模糊了逻辑。这里的一些结果将使代码更容易维护。由于一些随机的临时文件删除而跟踪随机的exeptions很烦人!您将如何处理关键部分的异常?

    代码

    public class Find
    {
            private Stack<File> fs=new Stack<File>();
            private Stack<File> ds=new Stack<File>();
            public Stack<File> getD(){ return ds;}
            public Stack<File> getF(){ return fs;}
    
            public Find(String path)
            {
                    // setting this type of special checks due to errs
                    // propagation makes the code clittered
                    if(path==null)
                    {
                            System.out.println("NULL in Find(path)");
                            System.exit(9);
                    }
                    this.walk(path);
            }
    
            private void walk( String path )
            {
                    File root = new File( path );
                    File[] list = root.listFiles();
    
                    //TODO: dangerous with empty try-catch?!
                    try{
                            for ( File f : list ) {
                                    if ( f.isDirectory() ) {
                                            walk( f.getAbsolutePath() );
                                            ds.push(f);
                                    }
                                    else {
                                            fs.push(f);
                                    }
                            }
                    }catch(Exception e){e.printStackTrace();}
            }
    }
    

    here.

    重构的代码

4 个答案:

答案 0 :(得分:4)

这是我可以将代码编写得最具可读性:

import java.util.*;
import java.io.*;

public class Find {
    List<File> files = new ArrayList<File>();
    List<File> dirs = new ArrayList<File>();
    List<Exception> excs = new ArrayList<Exception>();
    public Find(String path) {
        walk(new File(path));
    }
    void walk(File root) {
        for (File child : getChildren(root)) {
            if (isDirectory(child)) {
                dirs.add(child);
                walk(child);
            } else if (isFile(child)){
                files.add(child);
            }
        }
    }

(续)

    boolean isDirectory(File f) {
        try {
            return f.isDirectory();
        } catch (SecurityException e) {
            excs.add(e);
            return false;
        }
    }
    boolean isFile(File f) {
        try {
            return f.isFile();
        } catch (SecurityException e) {
            excs.add(e);
            return false;
        }
    }
    List<File> getChildren(File root) {
        File[] children;
        try {
            children = root.listFiles();
        } catch (SecurityException e) {
            excs.add(e);
            return Collections.emptyList();
        }
        if (children == null) {
            excs.add(new IOException("IOException|listFile|" + root));
            return Collections.emptyList();
        }
        return Arrays.asList(children);
    }
}

以下是一些重要的观察结果:

  • 无需检查pathnull
      如果File(String pathname)
    • NullPointerException会引发pathname == null
  • 无需像原始代码一样从String转到FileString等。
    • 只需处理File而不是
  • Effective Java 2nd Edition 第25项:首选列表到数组
  • 潜在抛出的File方法被封装到非抛出辅助方法中
    • 递归部分主逻辑是干净的
  • File.listFiles()File.isFile()File.isDirectory(),每个throws SecurityException
    • 事实证明,IOException不是投掷null而是返回IOException
      • 将其手动翻译为walk
  • 如果发现任何异常,只需返回不会干扰getChildren()的内容
    • 来自false
    • 的空列表 来自isFile(File)isDirectory(File)
    • catch (Exception e)
  • catch (SecurityException e)一般不好,所以我们只excs.add
  • 而不是{{1}},您实际上可以使用日志记录框架来记录异常

答案 1 :(得分:1)

使用空捕获忽略异常通常很危险。你必须使确定你将会发现的异常并不重要。

为了保持方法的逻辑清洁,您可以在另一种方法中提取错误处理代码。在那里,您可以放置​​所有必要的代码来识别错误的来源,并在需要时将其堆叠起来。

catch(Exception e){
    handleException();
}


private void handleException throws Exception() {...}

如果您关心跟踪递归中的异常,可以在方法参数中携带一个列表来堆叠异常,并在执行完成后立即处理它们。

private void walk(String path, List<Exception> listExceptions) {...}

通过这种方式,您可以忽略子路径上的错误,同时跟踪它并继续在树的其余部分执行。

答案 2 :(得分:0)

取决于您希望如何处理错误。

如果您现在使用您的代码遍历100个文件的目录,并且第二个文件导致异常,会发生什么?好吧,你在System.out中得到一个堆栈跟踪,walk方法将终止,没有更多的事情发生。 Find.getF()只包含第一个文件,程序的其余部分不会知道出错了。

这可能不是你想要的吗?

如果你知道你不关心某些错误(比如找不到文件),那么在你的循环中放一个try / catch块。在catch主体中,您只需记录该特定文件的确切错误,然后继续循环。通常,您不希望在此处记录完整的堆栈跟踪,只需一行。

如果你想以某种方式处理意外的异常,那么首先要决定你想要如何处理它们(只需登录并继续下一个文件?发送电子邮件?show user对话框?终止程序​​?),然后决定哪个类应该有责任处理意外错误。

如果您发现类的调用者应该处理意外错误,那么捕获并重新抛出您自己的异常是告诉调用者出错的好方法。 如果您确定Find类应该处理意外错误,那么将处理放入catch块。如果你想让循环在意外错误之后继续,那么移除你的外部try / catch并在循环中捕获所有东西。

答案 3 :(得分:0)

Poly-SO混合代码与Apache Commons FileUtils之间的比较:iterateFiles和listFiles

Apache commons-io在FileUtils中有类似的方法iterateFiles和listFiles,由Bozho建议。 参数检查以多种方式完成,但从不“System.exit(9)”! 他们comp为null,用File-type(可用的方法)检查​​它的存在, 他们在listFiles实现中使用static,linkedList - 由poly在书中提出。

他们重复使用该字段来匹配所有目录:

  

TrueFileFilter.INSTANCE             Singleton实例的真实过滤器(来自Apache API,单身?)

这两种方法是使用IOFileFilter作为参数的唯一方法。 我不确定它的影响。他们肯定可以重用他们的代码。

有一些非常简洁 - 我认为很好 - 评估点,没有模糊虚拟变量。 请查看(a?b:c)的评估,保存愚蠢的dums和if-clauses。

    return listFiles(directory, filter,
        (recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE));

方法所在的FileUtils类只有4个字段值 - 每个字段大约2.5个方法! 现在我被班上的羞辱。 一个显着的区别是使用例外。 他们使用它们 - 但显然由于FileUtils类的不同目标 - 它们让用户处理它们,而不是列表中的集中收集。 没有额外的声明。

<强>摘要

  • 相似:linkedList和list
  • 差异:较少的内容,较少的decs,较小的字段密度 - 方法 - succincy
  • 不同的目标:SO的最终用户案例,FileUtils更多后端
  • 差异(自然):SO中的异常处理但不是FileUtils中的异常处理(也许这就是它如此干净的原因)

我喜欢评论,特别是source - 比起阅读琐碎的API更好的教育目的,我觉得。希望你也是:)

Apache Commons:FileUtils.java,listFiles,iterateFiles - code pieces

/**
 * Finds files within a given directory (and optionally its
 * subdirectories). All files found are filtered by an IOFileFilter.
 * <p>
 * If your search should recurse into subdirectories you can pass in
 * an IOFileFilter for directories. You don't need to bind a
 * DirectoryFileFilter (via logical AND) to this filter. This method does
 * that for you.
 * <p>
 * An example: If you want to search through all directories called
 * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code>
 * <p>
 * Another common usage of this method is find files in a directory
 * tree but ignoring the directories generated CVS. You can simply pass
 * in <code>FileFilterUtils.makeCVSAware(null)</code>.
 *
 * @param directory  the directory to search in
 * @param fileFilter  filter to apply when finding files.
 * @param dirFilter  optional filter to apply when finding subdirectories.
 * If this parameter is <code>null</code>, subdirectories will not be included in the
 * search. Use TrueFileFilter.INSTANCE to match all directories.
 * @return an collection of java.io.File with the matching files
 * @see org.apache.commons.io.filefilter.FileFilterUtils
 * @see org.apache.commons.io.filefilter.NameFileFilter
 */
public static Collection listFiles(
        File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
    if (!directory.isDirectory()) {
        throw new IllegalArgumentException(
                "Parameter 'directory' is not a directory");
    }
    if (fileFilter == null) {
        throw new NullPointerException("Parameter 'fileFilter' is null");
    }

    //Setup effective file filter
    IOFileFilter effFileFilter = FileFilterUtils.andFileFilter(fileFilter,
        FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE));

    //Setup effective directory filter
    IOFileFilter effDirFilter;
    if (dirFilter == null) {
        effDirFilter = FalseFileFilter.INSTANCE;
    } else {
        effDirFilter = FileFilterUtils.andFileFilter(dirFilter,
            DirectoryFileFilter.INSTANCE);
    }

    //Find files
    Collection files = new java.util.LinkedList();
    innerListFiles(files, directory,
        FileFilterUtils.orFileFilter(effFileFilter, effDirFilter));
    return files;
}


/**
 * Allows iteration over the files in given directory (and optionally
 * its subdirectories).
 * <p>
 * All files found are filtered by an IOFileFilter. This method is
 * based on {@link #listFiles(File, IOFileFilter, IOFileFilter)}.
 *
 * @param directory  the directory to search in
 * @param fileFilter  filter to apply when finding files.
 * @param dirFilter  optional filter to apply when finding subdirectories.
 * If this parameter is <code>null</code>, subdirectories will not be included in the
 * search. Use TrueFileFilter.INSTANCE to match all directories.
 * @return an iterator of java.io.File for the matching files
 * @see org.apache.commons.io.filefilter.FileFilterUtils
 * @see org.apache.commons.io.filefilter.NameFileFilter
 * @since Commons IO 1.2
 */
public static Iterator iterateFiles(
        File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) {
    return listFiles(directory, fileFilter, dirFilter).iterator();
}

// ****切出一个部分****** //

/**
 * Finds files within a given directory (and optionally its subdirectories)
 * which match an array of extensions.
 *
 * @param directory  the directory to search in
 * @param extensions  an array of extensions, ex. {"java","xml"}. If this
 * parameter is <code>null</code>, all files are returned.
 * @param recursive  if true all subdirectories are searched as well
 * @return an collection of java.io.File with the matching files
 */
public static Collection listFiles(
        File directory, String[] extensions, boolean recursive) {
    IOFileFilter filter;
    if (extensions == null) {
        filter = TrueFileFilter.INSTANCE;
    } else {
        String[] suffixes = toSuffixes(extensions);
        filter = new SuffixFileFilter(suffixes);
    }
    return listFiles(directory, filter,
        (recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE));
}

/**
 * Allows iteration over the files in a given directory (and optionally
 * its subdirectories) which match an array of extensions. This method
 * is based on {@link #listFiles(File, String[], boolean)}.
 *
 * @param directory  the directory to search in
 * @param extensions  an array of extensions, ex. {"java","xml"}. If this
 * parameter is <code>null</code>, all files are returned.
 * @param recursive  if true all subdirectories are searched as well
 * @return an iterator of java.io.File with the matching files
 * @since Commons IO 1.2
 */
public static Iterator iterateFiles(
        File directory, String[] extensions, boolean recursive) {
    return listFiles(directory, extensions, recursive).iterator();
}