Корректный способ закрыть вложенные потоки и устройства записи в Java [дубликат]

Исправление ошибки: не удалось прослушать localhost:8000 (причина: адрес уже используется)

Список процессов с php в нем

ps -ef | grep php

Пример вывода

501  **9347**     393    0  1:29PM ttys000    0:00.21 php artisan serve
501    9351    **9347**  0  1:29PM ttys000    0:02.01 /usr/local/php5-5.6.14-20151002-085853/bin/php -S localhost:8000 .../laravel/server.php
501    9781       393    0  1:56PM ttys000    0:00.00 grep php

Затем убить процесс

kill -9 9347

92
задан Community 23 May 2017 в 11:33
поделиться

5 ответов

Обычно я делаю следующее. Во-первых, определите класс на основе шаблонного метода для работы с беспорядком try / catch

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

public abstract class AutoFileCloser {
    // the core action code that the implementer wants to run
    protected abstract void doWork() throws Throwable;

    // track a list of closeable thingies to close when finished
    private List<Closeable> closeables_ = new LinkedList<Closeable>();

    // give the implementer a way to track things to close
    // assumes this is called in order for nested closeables,
    // inner-most to outer-most
    protected final <T extends Closeable> T autoClose(T closeable) {
            closeables_.add(0, closeable);
            return closeable;
    }

    public AutoFileCloser() {
        // a variable to track a "meaningful" exception, in case
        // a close() throws an exception
        Throwable pending = null;

        try {
            doWork(); // do the real work

        } catch (Throwable throwable) {
            pending = throwable;

        } finally {
            // close the watched streams
            for (Closeable closeable : closeables_) {
                if (closeable != null) {
                    try {
                        closeable.close();
                    } catch (Throwable throwable) {
                        if (pending == null) {
                            pending = throwable;
                        }
                    }
                }
            }

            // if we had a pending exception, rethrow it
            // this is necessary b/c the close can throw an
            // exception, which would remove the pending
            // status of any exception thrown in the try block
            if (pending != null) {
                if (pending instanceof RuntimeException) {
                    throw (RuntimeException) pending;
                } else {
                    throw new RuntimeException(pending);
                }
            }
        }
    }
}

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

Наконец, сначала пытается закрыть снаружи любой декорированный поток, поэтому, если у вас был BufferedWriter, оборачивающий FileWriter, мы сначала пытаемся закрыть BuffereredWriter, а если это не удается, все равно пытаемся закрыть сам FileWriter. (Обратите внимание, что определение Closeable вызывает close () для игнорирования вызова, если поток уже закрыт)

Вы можете использовать приведенный выше класс следующим образом:

try {
    // ...

    new AutoFileCloser() {
        @Override protected void doWork() throws Throwable {
            // declare variables for the readers and "watch" them
            FileReader fileReader = 
                    autoClose(fileReader = new FileReader("somefile"));
            BufferedReader bufferedReader = 
                    autoClose(bufferedReader = new BufferedReader(fileReader));

            // ... do something with bufferedReader

            // if you need more than one reader or writer
            FileWriter fileWriter = 
                    autoClose(fileWriter = new FileWriter("someOtherFile"));
            BufferedWriter bufferedWriter = 
                    autoClose(bufferedWriter = new BufferedWriter(fileWriter));

            // ... do something with bufferedWriter
        }
    };

    // .. other logic, maybe more AutoFileClosers

} catch (RuntimeException e) {
    // report or log the exception
}

Используя этот подход, вам никогда не придется беспокоиться о try / catch / finally, чтобы снова разобраться с закрытием файлов.

Если это слишком сложно для вашего использования,

19
ответ дан 24 November 2019 в 06:34
поделиться

Это на удивление неудобный вопрос. (Даже если предположить, что получить; попробовать {использовать;} finally {release;} код верен.)

Если конструкция декоратора завершится неудачно, то вы не закроете базовый поток. Поэтому вам нужно явно закрыть базовый поток, будь то в конце после использования или, что еще сложнее, после успешной передачи ресурса декоратору).

Если исключение вызывает сбой выполнения, вы действительно хотите сбросить?

У некоторых декораторов есть ресурсы. Текущая реализация Sun ZipInputStream , например, имеет выделенную память кучи, отличную от Java.

Было заявлено, что (IIRC) две трети ресурсов, используемых в библиотеке Java, реализованы явно неправильным образом .

В то время как BufferedOutputStream закрывается даже при IOException из flush , BufferedWriter закрывается правильно.

Мой совет: Закройте ресурсы как напрямую, насколько это возможно, и не позволяйте им портить другой код. OTOH, вы можете потратить слишком много времени на эту проблему - если выдается OutOfMemoryError , неплохо вести себя прилично, но другие аспекты вашей программы, вероятно, имеют более высокий приоритет, и код библиотеки, вероятно, в этой ситуации все равно сломан. Но я всегда писал:

final FileOutputStream rawOut = new FileOutputStream(file);
try {
    OutputStream out = new BufferedOutputStream(rawOut);
    ... write stuff out ...
    out.flush();
} finally {
    rawOut.close();
}

(Смотрите: без уловки!)

И, возможно, использовал идиому Execute Around.

не позволять им портить другой код. OTOH, вы можете потратить слишком много времени на эту проблему - если выдается OutOfMemoryError , неплохо вести себя прилично, но другие аспекты вашей программы, вероятно, имеют более высокий приоритет, и код библиотеки, вероятно, в этой ситуации все равно сломан. Но я всегда писал:

final FileOutputStream rawOut = new FileOutputStream(file);
try {
    OutputStream out = new BufferedOutputStream(rawOut);
    ... write stuff out ...
    out.flush();
} finally {
    rawOut.close();
}

(Смотрите: без уловки!)

И, возможно, использовал идиому Execute Around.

не позволять им портить другой код. OTOH, вы можете потратить слишком много времени на эту проблему - если выдается OutOfMemoryError , неплохо вести себя прилично, но другие аспекты вашей программы, вероятно, имеют более высокий приоритет, и код библиотеки, вероятно, в этой ситуации все равно сломан. Но я всегда писал:

final FileOutputStream rawOut = new FileOutputStream(file);
try {
    OutputStream out = new BufferedOutputStream(rawOut);
    ... write stuff out ...
    out.flush();
} finally {
    rawOut.close();
}

(Смотрите: без уловки!)

И, возможно, использовал идиому Execute Around.

5
ответ дан 24 November 2019 в 06:34
поделиться

Sun's JavaDocs include RuntimeExceptions in their documentation, as shown by InputStream's read(byte[], int, int) method; documented as throwing NullPointerException and IndexOutOfBoundsException.

FilterOutputStream's flush() is only documented as throwing IOException, thus it doesn't actually throw any RuntimeExceptions. Any that could be thrown would most likely be wrapped in an IIOException.

It could still throw an Error, but there's not much you can do about those; Sun recommends that you don't try to catch them.

-1
ответ дан 24 November 2019 в 06:34
поделиться

При закрытии связанных потоков вам нужно только закрыть самый внешний поток. Любые ошибки будут распространяться вверх по цепочке и обнаруживаться.

Подробнее см. Потоки ввода-вывода Java .

Для решения проблемы

Однако, если flush () вызывает среду выполнения исключение по какой-то причине, то out.close () никогда не будет вызываться.

Это неправильно. После того, как вы поймаете и проигнорируете это исключение, выполнение возобновится после блока catch, и будет выполнен оператор out.close () .

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

39
ответ дан 24 November 2019 в 06:34
поделиться

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

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

5
ответ дан 24 November 2019 в 06:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: