Требуется ли для вложенных ресурсов специальная обработка в Java? - PullRequest
0 голосов
/ 25 января 2019

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

Давайте посмотрим на этот код из документации Javaв качестве примера, который можно найти здесь :

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

Теперь ресурс освобождается br.close(), если он был получен.Однако

  • Что произойдет, если new FileReader(path) завершится успешно, а затем new BufferedReader(...) сгенерирует исключение?
  • Как Java гарантирует, что FileReader закрыт?
  • Гарантируется ли, что создание BufferedReader на уже открытом FileReader всегда будет успешным?Если так, почему этот метод объявлен как выбрасывающий IOException?

Или мы должны вместо этого написать следующее, чтобы убедиться, что ситуация не возникает?

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {

    FileReader fr;

    try {
        FileReader fr = new FileReader(path);
        BufferedReader br;
        try {
            BufferedReader br = new BufferedReader(fr);
            return br.readLine();
        } finally {
            if (br != null) br.close();
        }
    finally {
        // Implements closeable, so it is ok if we call it twice.
        if (fr != null) fr.close();
    }
}


Конечно, при использовании try-with-resources этот вложенный беспорядок все же исчезает, поскольку мы можем объявить несколько ресурсов в одном выражении.Но я всегда вижу, что пишу «попробуй с ресурсами», чтобы вообще не думать об этой ситуации и пытаться найти решение в Интернете, которого я действительно не смог.

Любая помощь будет признательна, спасибо!

Ответы [ 4 ]

0 голосов
/ 25 января 2019

Уроки часто устарели или не описывают хорошую практику.

Если мы посмотрим на первый фрагмент кода, который вы процитировали, br никогда не может быть null.if ( ) можно удалить.Вероятно, это было вызвано предыдущим кодом из-за предыдущего микширования кода до finally с catch.Если оператор try имеет и finally, и catch, это, вероятно, неправильно и почти наверняка делает что-то дурное.Обычно вы наблюдаете танец null и по крайней мере одну очевидную ошибку.

Полученная мудрость в этом вопросе заключается в том, что BufferedReader потерпит неудачу, только если что-то пошло не так со всем вашим процессом.Возможно, недостаточно памяти или стек переполнен.Если вы получаете такого рода исключения, вы, вероятно, захотите спасти их вообще.

Педантичный способ написания кода без try-with-resource:

FileReader fr = new FileReader(path);
try {
    BufferedReader br = new BufferedReader(fr);
    return br.readLine();
} finally {
    fr.close();
}

Однако в некоторыхна случай, если вы ошибетесь.Считается BufferWriter.Вы забыли flush, не так ли?Я имею в виду, я бы.Если вы закроете это в finally, это не будет проблемой.Также некоторые декораторы сами являются ресурсами.Например, они могут иметь встроенную реализацию, которая использует не собранную память.Это не обязательно задокументировано.

Закрытие как ресурса, так и декоратора не сложно, но движется вправо без попытки с ресурсом.

// (Using same example even though it doesn't matter here - imaging a Writer)
FileReader fr = new FileReader(path);
try {
    BufferedReader br = new BufferedReader(fr);
    try {
        return br.readLine();
    } finally {
        br.close();
    }
} finally {
    fr.close();
}
0 голосов
/ 25 января 2019

Что произойдет, если новый FileReader (путь) завершится успешно, а затем новый BufferedReader (...) сгенерирует исключение?

Конструктор BufferedReader не сгенерирует исключения.В частности, он не включает какие-либо операции с файловой системой, поэтому он не генерирует IOException.

Как java гарантирует закрытие FileReader?

Закрытие BufferedReaderметод закрывает базовый FileReader.

Гарантируется ли, что создание BufferedReader на уже открытом FileReader всегда будет успешным?Если так, почему этот метод объявлен как выбрасывающий IOException?

Вы сосредоточены не на том, что нужно.readFirstLineFromFileWithFinallyBlock помечен throws IOException, потому что каждый вызванный метод или конструктор, кроме конструктора BufferedReader, может генерировать IOException.readline, close и конструктор FileReader могут выдавать все значения.


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

0 голосов
/ 25 января 2019

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

try(BufferedReader bufferedReader = new BufferedReader(new FileReader(""))) {

    }catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
0 голосов
/ 25 января 2019

Посмотрите в исходном коде Java на реализацию close() для BufferedReader.

 * @see FileReader
 * @see InputStreamReader
 * @see java.nio.file.Files#newBufferedReader
 *
 * @author      Mark Reinhold
 * @since       1.1
 */

public class BufferedReader extends Reader {

private Reader in;

...
 public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        try {
            in.close();
        } finally {
            in = null;
            cb = null;
        }
    }
}
...
  /**
 * Creates a buffering character-input stream that uses an input buffer of
 * the specified size.
 *
 * @param  in   A Reader
 * @param  sz   Input-buffer size
 *
 * @exception  IllegalArgumentException  If {@code sz <= 0}
 */
public BufferedReader(Reader in, int sz) {
    super(in);
    if (sz <= 0)
        throw new IllegalArgumentException("Buffer size <= 0");
    this.in = in;
    cb = new char[sz];
    nextChar = nChars = 0;
}

/**
 * Creates a buffering character-input stream that uses a default-sized
 * input buffer.
 *
 * @param  in   A Reader
 */
public BufferedReader(Reader in) {
    this(in, defaultCharBufferSize);
}

, так что close () позаботился о Reader (FileReader здесь) и установите для него значение null.
Просто BufferedReader br = new BufferedReader(new FileReader(path)) хорошо

Требует ли специальная обработка вложенных ресурсов в Java?


здесь: НЕТ

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