【问题标题】:Java: dangerous self-returning-recursive function by IOException?Java:IOException 的危险自返回递归函数?
【发布时间】:2010-04-12 16:00:25
【问题描述】:

我在使用 if 子句时遇到了非常错误的异常处理。如果找不到路径,则会发生异常。异常再次返回该函数。该函数是递归的。安全吗?

$ javac SubDirs.java $ java子目录 给我一条路。 . 目录1 目录2 给我一条路。 它不会找到我,所以它会返回自己,因为捕获到异常 给我一条路。

Subdirs.java的代码如下:

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

public class SubDirs {
    private List<File> getSubdirs(File file) throws IOException {
        List<File> subdirs = Arrays.asList(file.listFiles(new FileFilter() {
                    public boolean accept(File f) {
                    return f.isDirectory();
                    }
                    }));
        subdirs = new ArrayList<File>(subdirs);

        List<File> deepSubdirs = new ArrayList<File>();
        for(File subdir : subdirs) {
            deepSubdirs.addAll(getSubdirs(subdir)); 
        }
        subdirs.addAll(deepSubdirs);
        return subdirs;
    }

    public static void search() {
        try{
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String s;
            System.out.println("Give me an path.");
            while ((s = in.readLine()) != null && s.length() != 0){
                SubDirs dirs = new SubDirs();
                List<File> subDirs = dirs.getSubdirs(new File(s));
                for ( File f : subDirs ) {
                    System.out.println(f.getName());
                }
                System.out.println("Give me an path.");
            }
        }catch(Exception e){
                    // Simple but is it safe?
            search();
        }
    }

    public static void main(String[] args) throws IOException {
        search();
    }
}

【问题讨论】:

  • 您能重新表述一下您的问题吗?我很难理解你在问什么。
  • @Sauer:设 A 为递归函数。根据定义,B 是递归的,因为它返回 A。使用 try-catch-loop 具有内部递归函数的递归函数是否安全?
  • B 返回自身。 A返回自己。 B 具有 A 作为内部结构。 A 是 getSubDirs,B 是搜索。

标签: java error-handling recursion


【解决方案1】:

是的,在您输入错误路径数千次之前是安全的。

【讨论】:

    【解决方案2】:

    值得商榷。我认为这会留下一堆无用的堆栈帧 - 除非您尝试在移动设备上重用此代码,否则这可能不是问题。 无论如何,如果没有更好的方法,我不会让它通过代码审查。

    为了更好的可理解性和可维护性,养成按你的意思编写代码的习惯:如果你打算循环代码以重试错误,那么就编写一个循环代码。递归感觉更流畅,但是,由于它不是异常处理程序中的常见做法,它增加了意外因素。如果我是此代码的未来维护者,我想知道递归是有意的还是错误 - 请给我留言以解释递归是有意的。

    我现在很乐意多交换几行普通代码,以便以后更好的可维护性和更容易的故障排除。

    public static void search() {
    
      boolean succeeded = false;
      int attemptsLeft = MAX_ATTEMPTS;
      while (! succeeded && (--attemptsLeft > 0)) {
    
        try{
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String s;
            System.out.println("Give me an path.");
            while ((s = in.readLine()) != null && s.length() != 0){
                SubDirs dirs = new SubDirs();
                List<File> subDirs = dirs.getSubdirs(new File(s));
                for ( File f : subDirs ) {
                    System.out.println(f.getName());
                }
                System.out.println("Give me an path.");
            }
    
            succeeded = true;
    
        }catch(Exception e){
            // ALWAYS LEAVE YOURSELF A CLUE TO WHAT HAPPENED
            // e.g. the exception caught may not be the exception you expected
            e.printStackTrace();
        }
    
      } // while not succeeded yet
    
      if (! succeeded) {
        log("Hmm ... bailing search() without succeeding");
      }
    }
    

    【讨论】:

      【解决方案3】:

      每次 search() 失败时,您都会在调用堆栈上创建另一个 search() 实例。在这种情况下,它会提示用户输入,我想用户很可能在溢出你的堆栈之前很久就放弃了,所以我认为这里的危险是最小的。但是,如果您有一个应用程序重新尝试失败或移动到可能很长的列表中的下一个项目,您可能会使用这种方法溢出堆栈。

      我建议一个更好的方法是将 try/catch 块放在您的 while 循环中,并在失败时再次执行循环,而不是进行递归调用。类似于 -- WARNING -- 未经测试的建议代码:

      public static void search() { 
          BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
          String s; 
          System.out.println("Give me an path."); 
          while ((s = in.readLine()) != null && s.length() != 0){ 
              try
              { 
                  SubDirs dirs = new SubDirs(); 
                  List<File> subDirs = dirs.getSubdirs(new File(s)); 
                  for ( File f : subDirs ) { 
                      System.out.println(f.getName()); 
                  }
              }
              catch (Exception e) {
                  System.out.println("Something went wrong! Everybody scream and run in circles!");
              }
          System.out.println("Give me an path."); 
          } 
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-16
        • 1970-01-01
        • 2023-03-08
        • 2021-12-01
        相关资源
        最近更新 更多