Как упростить / повторно использовать этот код обработки исключений - PullRequest
5 голосов
/ 11 октября 2010

Я часто пишу код, подобный следующему:

BufferedWriter w = null; // Or any other object that throws exceptions and needs to be closed
try {
    w = new BufferedWriter(new FileWriter(file));
    // Do something with w
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (w != null) {
        try {
            w.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

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

Мне было интересно, может ли приведенный выше код быть упрощен или использован каким-либо образом.

Ответы [ 8 ]

6 голосов
/ 11 октября 2010

Если вы не хотите писать код для закрытия в блоке finally, вам следует взглянуть на Project Lombok

Вместо написания нормального

public class CleanupExample {
  public static void main(String[] args) throws IOException {
  InputStream in = new FileInputStream(args[0]);
  try {
    OutputStream out = new FileOutputStream(args[1]);
    try {
      byte[] b = new byte[10000];
      while (true) {
         int r = in.read(b);
         if (r == -1) break;
         out.write(b, 0, r);
      }
    } finally {
        out.close();
      }
  } finally {
     in.close();
    }
  }
}

С помощью Lombok вы можете написать

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
   }
 }

Гораздо более читабельно, и он генерирует правильный способ закрытия потока. Это работает со всеми Closeable интерфейсами

5 голосов
/ 11 октября 2010

Я обычно помещаю содержимое вашего блока finally в помощник. Как это

void close(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException e) {
            // perform logging or just ignore error
        }
    }
}

Closeable интерфейс реализован многими классами (входные потоки, соединения с базой данных и т. Д.), Так что это своего рода помощник общего назначения.

4 голосов
/ 11 октября 2010

Да, так как в Java 1.5 есть закрываемый интерфейс. У вас может быть статический метод, который закрывает любой тип Closeable.

  public static void closeIO(Closeable closeable){
      if (closeable != null) {
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
3 голосов
/ 11 октября 2010

Java 7 пытается с поддержкой ресурсов. Проверьте это для получения дополнительной информации.

Я цитирую соответствующий текст и пример кода здесь:

с новой функцией языка try-with-resource в Java 7 вы фактически объявляете свои потоковые аргументы как часть try-construct, а компилятор генерирует код, который автоматически и чисто управляет этими ресурсами.

private static void customBufferStreamCopy(File source, File target) {
    try (InputStream fis = new FileInputStream(source);
        OutputStream fos = new FileOutputStream(target)){

        byte[] buf = new byte[8192];

        int i;
        while ((i = fis.read(buf)) != -1) {
            fos.write(buf, 0, i);
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}
1 голос
/ 11 октября 2010

Я считаю, что обычно лучше не пытаться поймать и, наконец, все в одном блоке.Часто лучше иметь блок try-catch и отдельный блок try-finally.

try {
    BufferedWriter w = new BufferedWriter(new FileWriter(file)); // Or any other object that throws exceptions and needs to be closed
    try {
        // Do something with w
    } finally {
        w.close();
    }
} catch (IOException e) {
    e.printStackTrace();
}

Это также избавляет от необходимости проверки нуля w.

1 голос
/ 11 октября 2010

Я склонен согласиться с другими, которые предлагают метод, принимающий Closeable, но из-за обслуживания очень долгоживущих программ, решение, которое я использую, немного отличается. По сути, для обеспечения гибкости требуется OutputStream.

public class IOHandler {

  private IOHandler();

  public static void close(OutputStream out, Closeable c) {
    if (c != null) {
      try {
        c.close();
    } catch (IOException e) {
        out.print(c.printStackTrace().getBytes());
    }
  }

}

Основным преимуществом этого является то, что вы можете вызывать его различными способами, устраняя необходимость в специализированных утилитах для обработки исключений при регистрации в stderr, stdout и файлах.

IOHandler.close(System.out, openFile);
IOHandler.close(System.err, openFile);
IOHandler.close(logFile, openFile);

Кроме этой добавленной функции, это в основном то же решение, которое предлагали другие.

0 голосов
/ 11 октября 2010

Здесь можно применить шаблонный метод:

public class FileTemplate {
    public void write(File file, WriteCallback c) {
        BufferedWriter w = null; // Or any other object that throws exceptions and needs to be closed 
        try { 
            w = new BufferedWriter(new FileWriter(file)); 
            c.writeFile(w); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } finally { 
            if (w != null) { 
                try { 
                    w.close(); 
                } catch (IOException e) { 
                    e.printStackTrace(); 
                } 
            } 
        }
    }
}

public interface WriteCallback {
    public void writeFile(BufferedWriter w) throws IOException;
}

.

new FileTemplate().write(file, new WriteCallback() {
    public void writeFile(BufferedWriter w) { ... }
});
0 голосов
/ 11 октября 2010

Запишите это методом ...

BuffereWriter getMyWriter()
{

// your code....

return w;
}
...