searh使用递归定义的函数,可以轻松抛出异常。我已经尝试了3种处理exeptions的方法:
一些例外情况我不会像执行期间那样关心删除文件-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();}
}
}
重构的代码
答案 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);
}
}
以下是一些重要的观察结果:
path
是null
File(String pathname)
NullPointerException
会引发pathname == null
String
转到File
到String
等。
File
而不是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)
使用空捕获忽略异常通常很危险。你必须使确定你将会发现的异常并不重要。
为了保持方法的逻辑清洁,您可以在另一种方法中提取错误处理代码。在那里,您可以放置所有必要的代码来识别错误的来源,并在需要时将其堆叠起来。
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类的不同目标 - 它们让用户处理它们,而不是列表中的集中收集。 没有额外的声明。
<强>摘要强>
我喜欢评论,特别是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();
}