Java: обработка ошибок с помощью try-catch, empty-try-catch, dummy-return - PullRequest
2 голосов
/ 05 мая 2010

Поиск использует рекурсивно определенную функцию, которая легко генерирует исключения. Я пробовал 3 способа обработки исключений:

  1. игнорировать с помощью empty-try-catch ()
  2. add-dummy-return остановка err-распространения из-за исключения
  3. бросить конкретное, кроме. (эту часть я не совсем понимаю. Если я выброшу, кроме как, могу ли я заставить его продолжить в другом месте, не продолжая старый путь кроме-брошенного?)

Некоторые исключения меня не особо волнуют, например, во время выполнения удаленных файлов - исключение (NullPointer), но некоторые мне действительно нравятся неизвестные вещи.

Возможные исключения:

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

Код очень важен для всей программы. Ранее я добавил clittered-check, try-catches, избежать-empty-try-catches, но это действительно размыло логику. Некоторые каменные результаты сделают код позже намного проще в обслуживании. Было очень неприятно отслеживать случайные исключения из-за некоторого случайного удаления временного файла! Как бы вы обработали исключения для критической части?

Код

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

Код с номером здесь.

Ответы [ 4 ]

4 голосов
/ 05 мая 2010

Это наиболее читаемый код, из которого я могу сделать код:

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 вместо
  • Effective Java 2nd Edition Элемент 25: Предпочитать списки массивам
  • Потенциально бросающие методы File инкапсулированы в не бросающие вспомогательные методы.
    • Основная логика рекурсивной части чиста таким образом
  • File.listFiles(), File.isFile() и File.isDirectory(), каждый throws SecurityException
    • Оказывается, вместо IOException, listFiles() вернет null
      • Это переводится вручную в IOException
  • Если обнаружится какое-либо исключение, просто верните что-нибудь, что не помешает walk
    • пустой список из getChildren()
    • false от isFile(File) и isDirectory(File)
  • catch (Exception e) в целом плохо, поэтому мы только catch (SecurityException e)
  • Вместо excs.add, вы можете использовать каркас регистрации для регистрации исключения
1 голос
/ 05 мая 2010

Игнорирование исключения с пустым уловом обычно опасно. Вы должны сделать уверен исключение, которое вы поймете там, не имеют никакого значения для выполнения.

Чтобы сохранить логику метода в чистоте, вы можете извлечь код обработки ошибок в другом методе. Там вы можете поместить весь необходимый код, чтобы определить источник ошибки, и при необходимости составить его.

catch(Exception e){
    handleException();
}


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

Если вы заботитесь о том, чтобы отслеживать исключения в своей рекурсии, вы можете вести список параметров вашего метода, чтобы объединять исключения и обрабатывать их сразу после завершения выполнения.

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

Таким образом, вы можете игнорировать ошибку в подпути, отслеживая ее и продолжая выполнение для остальной части вашего дерева.

0 голосов
/ 05 мая 2010

Сравнение кода смешивания Poly-SO и FileUtils Apache Commons: iterateFiles и listFiles

Apache commons-io имеет аналогичные методы iterateFiles и listFiles в FileUtils, предложенные Bozho . Проверка параметров выполняется разными способами, но никогда не "System.exit (9)"! Они сравнивают с нулем, проверяют его существование с помощью File-type (доступный для него метод), Они используют static, relatedList в реализации listFiles - предложено в книге poly .

Они повторно используют поле, чтобы найти все каталоги:

TrueFileFilter.INSTANCE Синглтонный экземпляр истинного фильтра (из API Apache, синглтон?)

Эти два метода являются единственными, которые используют IOFileFilter в качестве параметра. Я не уверен в его последствиях. Они наверняка могут повторно использовать свой код.

Есть несколько очень кратких - я думаю, хороших - оценочных баллов, никаких размытых пустышек. Пожалуйста, посмотрите оценку (a? B: c), сохраните глупые суммы и предложения if.

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

Класс FileUtils, в котором находятся методы, имеет только 4 значения поля - около 2,5 методов на поле! Теперь мне стыдно за мой класс. Разительная разница заключается в использовании исключений. Они используют их, но - очевидно, из-за другой цели класса FileUtils - они позволяют пользователю обрабатывать их, нет централизованной коллекции в списке. Никаких дополнительных объявлений.

Основная информация

  • Схожесть: связанный список и список
  • Различия: меньше единиц, меньше разрядов, меньшая плотность полей для методов - краткость
  • Различные цели: пример класса SO для конечного пользователя, FileUtils более бэкэнд
  • Различие (естественное): обработка исключений в SO, но не в FileUtils (возможно, поэтому она так чиста)

Мне понравились комментарии и, в частности, источник 1039 * - я считаю, что он гораздо лучше в образовательных целях, чем чтение простых API. Надеюсь, вы тоже:)

Apache Commons: 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();
}
0 голосов
/ 05 мая 2010

Зависит от того, как вы хотите обрабатывать ошибки.

Если вы сейчас просматриваете каталог из 100 файлов с вашим кодом, а второй файл вызывает исключение, что произойдет? Что ж, вы получаете трассировку стека в System.out, метод walk завершается и больше ничего не происходит. Find.getF () будет содержать только первый файл, и остальная часть вашей программы не будет знать, что что-то пошло не так.

Это, вероятно, не так, как вы хотите?

Если вы знаете, что вас не волнуют некоторые ошибки (например, файл не найден), поместите блок try / catch для этого внутри цикла. В теле catch вы просто регистрируете, что именно пошло не так с этим конкретным файлом, и затем вы продолжаете в своем цикле. Часто вы не хотите регистрировать здесь полные трассировки стека, только одну строку.

Если вы хотите как-то обрабатывать неожиданные исключения, то сначала решите, как вы хотите их обработать (просто войдите в систему и перейдите к следующему файлу? Отправьте электронное письмо? несут ответственность за обработку непредвиденных ошибок.

Если вы обнаружите, что вызывающий ваш класс должен обрабатывать непредвиденные ошибки, то перехват и повторное создание собственного исключения - хороший способ сообщить вызывающему, что что-то пошло не так. Если вы решите, что ваш класс Find должен обрабатывать непредвиденные ошибки, поместите обработку в ваш блок catch. Если вы хотите, чтобы цикл продолжался даже после непредвиденных ошибок, удалите внешнюю команду try / catch и выполните все перехваты внутри цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...