代码之家  ›  专栏  ›  技术社区  ›  hhh

Java:try-catch、空try-catch、伪返回的错误处理

  •  2
  • hhh  · 技术社区  · 16 年前

    searh使用递归定义的函数,很容易抛出异常。我尝试了3种处理例外的方法:

    1. 使用空try-catch()忽略
    2. 添加由于exeption导致的dummy return stop err传播
    3. 抛出一个特定的例外(这部分我不太明白。如果我抛出except,我是否可以强制它在其他地方继续,而不是继续旧的except抛出路径?)

    可能的例外情况:

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

    这段代码对整个程序非常重要。我之前添加了clittered checks,try-catch,避免了空的try-catch,但它确实模糊了逻辑。这里的一些错误结果将使代码更易于维护。由于一些随机的临时文件删除,跟踪随机的例外是很烦人的!您将如何处理关键部分的异常?

    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 回复  |  直到 9 年前
        1
  •  4
  •   polygenelubricants    16 年前

    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);
        }
    }
    

    以下是一些关键观察结果:

    • 不需要检查 path null
      • File(String pathname) 投掷 NullPointerException 如果 pathname == null
    • 没有必要离开 String File 到 字符串
      • 文件 相反
    • 第25项:首选列表而不是数组
    • 潜在的抛掷 方法被封装到非抛出辅助方法中
      • 递归部分的主逻辑是干净的
    • File.listFiles() , File.isFile() 和 File.isDirectory() throws SecurityException
      • IOException , listFiles() 无效的 相反
        • 这是手动翻译成 IOException异常
    • 如果捕获到任何异常,只需返回一些不会干扰 walk
      • getChildren()
      • false 从 isFile(File) 和 isDirectory(File)
    • catch (Exception e) 一般来说是不好的,所以我们 catch (SecurityException e)
    • 而不是 excs.add ,实际上可以使用日志框架来记录异常
        2
  •  1
  •   Etienne    16 年前

    忽略带有空捕获的异常通常是危险的。你必须做出决定 你将在那里发现的例外对执行没有任何重要性。

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

    catch(Exception e){
        handleException();
    }
    
    
    private void handleException throws Exception() {...}
    

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

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

        3
  •  0
  •   rompetroll    16 年前

    如果现在用代码遍历包含100个文件的目录,而第二个文件导致异常,会发生什么情况?好吧,如果在System.out中得到一个stacktrace,walk方法将终止,不再发生任何事情。getF()将只包含第一个文件,而程序的其余部分将不知道发生了什么错误。

    如果你知道你不关心一些错误(比如找不到文件),那么在你的循环中放一个try/catch块。在catch body中,您只需记录特定文件的具体错误,然后继续循环。通常您不想在这里记录完整的stacktraces,只需要一行。

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

    如果发现类的调用者应该处理意外错误,那么捕获并重新引发自己的异常是告诉调用者出了问题的好方法。 如果您决定Find类应该处理意外错误,那么将处理放入catch块中。如果希望循环即使在发生意外错误后仍能继续,请删除外部try/catch并在循环内执行所有捕获。

        4
  •  0
  •   Community Mohan Dere    9 年前

    Poly-SO-mix代码与Apache-Commons-FileUtils的比较:iterateFiles和listFiles

    apachecommons io在FileUtils中有类似的方法iterateFiles和listFiles,由 Bozho 参数检查有多种方式,但从不使用“System.exit(9)”! 他们在listFiles实现中使用静态的linkedList,这是作者在书中建议的 poly .

    它们重用字段以匹配所有目录:

    TrueFileFilter.INSTANCE实例 true filter的单例实例(来自apacheapi,Singleton?)

    我不确定它的含义。他们当然可以重用他们的代码。

    有一些非常简洁的——我觉得不错——评估点,没有模糊的虚拟变量。

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

    方法所在的FileUtils类只有4个字段值——每个字段大约有2.5个方法! 现在我为我的班级感到羞愧。 它们使用它们,但显然由于FileUtils类的不同目标,它们允许用户处理它们,列表中没有集中的集合。 没有额外的声明。

    • 相似性:linkedList和list
    • 不同之处:init更少,dec更少,方法的字段密度更小——简洁
    • 不同的目标:所以类的最终用户情况,FileUtils更多的后端
    • 区别(自然):在SO中处理异常,而不是在FileUtils中(也许这就是它如此干净的原因)

    我喜欢评论,尤其是 source

    apachecommons:FileUtils.java、listFiles、iterateFiles-代码片段

    /**
     * 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();
    }
    
    推荐文章