Почему мы должны как объявлять, так и определять ресурсы в блоке try-with-resource?

try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}

Выше работает отлично. Но, когда я делаю

PrintWriter f;
try(f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
{}
catch(IOException ex) 
{
  ex.printStackTrace();
}

Это бросает ошибки. Почему это так? Я тестировал эту новую функцию, и я придерживался мнения, что я выберу второй метод и после try-catch statement распечатал бы ресурс PrintWriter f - который должен быть нулевым, если оператор try-with-resource работает, как ожидалось. Почему 2-й путь не разрешен?

Также, как я мог проверить это методом 1?

3 ответа

Так как try-with-resources на самом деле добавляет finally заблокировать для вас, чтобы закрыть ресурсы после использования, чтобы они не могли быть использованы в любом случае (после того, как вы оставите try блок).

Итак, этот код

try(PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) {

} catch(IOException ex) {
    ex.printStackTrace();
}

на самом деле переводится в

PrintWriter f = null;
try {
    f = new PrintWriter(new BufferedWriter(new FileWriter("abc.txt")));) 
     // now do something
} catch(IOException ex) {
    ex.printStackTrace();
}
finally {
    try {
        f.close();
        catch(IOException ex) {}
     }
}

Так что это была первоначальная цель, избавить вас от раздутого кода и позволить вам позаботиться о try заблокировать и оставить остальное на JVM. Также посмотрите, что Oracle по этому поводу скажет.

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

    PrintWriter t = null;
    try( PrintWriter f = new PrintWriter( new BufferedWriter(
            new FileWriter( "abc.txt" ) ) ) ) {
        f.println( "bar" );
        t = f;
    } catch( IOException ex ) {
        ex.printStackTrace();
    }
    System.out.println( t );
    t.println( "foo" );
    t.close();

Выход:

java.io.PrintWriter@1fc4bec

Но ничего не добавляется в файл, так как автор был закрыт при попытке.

Редактировать: Если вы хотите играть с TWR, напишите класс, который реализует AutoClosable, например:

public class Door implements AutoCloseable {
    public Door() {
        System.out.println( "I'm opening" );
    }
    public void close() {
        System.out.println( "I'm closing" );
    }
    public static void main( String[] args ) {
        try( Door door = new Door() ) { }
    }

}

Выход:

Я открываю

Я закрываю

Не совсем уверен, но делаю некоторые сложные предположения:

  • Значение f после блока catch потенциально не определено. Поэтому вам нужно будет добавить все виды проверок, чтобы проверить, был ли Объект создан, использован и / или закрыт. Но если вам нужны все эти проверки, было бы проще вообще не использовать эту идиому.

  • JIT может успешно оптимизировать код с помощью локальной блочной переменной.

  • Переменная AutoClosure не должна быть установлена ​​на другую переменную во время блока try, но может быть впоследствии. Может быть, это слишком сложно для проверки JIT.

Другие вопросы по тегам