Будет ли отдельный ресурс в попытке с оператором ресурса не закрыт, если из оператора выдается исключение (проблема инициализации) - PullRequest
0 голосов
/ 01 ноября 2018

Пример кода:

    class TestCharStream {
        public static void main(String[] args){
// Assume specified file is not available in the location
            try (Reader reader = new FileReader("C:\\TestData\\test123.txt")) {
                System.out.println("Entered Try block");
                int content;
                while ((content = reader.read()) != -1) {
                    System.out.print((char) content);
                }

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

Поскольку файл недоступен, будет сгенерировано «FileNotFoundException», и ресурс не будет инициализирован.

Из спецификации Java SE7 я понимаю следующие пункты, относящиеся к выражению «попробуй с ресурсами»

  • Если ресурс не инициализируется (то есть его выражение инициализатора вызывает исключение), то все ресурсы, инициализированные до сих пор оператором try-with-resources, закрываются.
  • Ресурс закрывается, только если он инициализирован ненулевым значением.
  • Если исключения вызываются как из блока try, так и из оператора try-with-resources, то метод выдает исключение, выброшенное из блока try; исключение, выброшенное из оператора try-with-resources, подавлено.

У меня есть вопросы, касающиеся закрытия ресурсов, исключения исключений, связанных с пунктами, указанными выше

1) Не попадает ли приведенный выше пример кода (т. Е. Ресурс не удалось инициализировать) в сценарий .. ресурс будет закрыт независимо от того, завершается ли оператор try нормально или внезапно . Это применимо только к ресурсам, успешно инициализированным в операторе try с оператором ресурсов, и в блоке try есть ошибка?

2) Если при инициализации ресурсов возникают исключения (как в примере), это попадет в сценарий неудачной инициализации. В этом случае, как мы можем встретить сценарий исключений, брошенный в оператор try-with-resources (который может в основном происходить только во время инициализации) вообще? Это исключения, возникающие при закрытии ресурса?

Ответы [ 3 ]

0 голосов
/ 01 ноября 2018

1) В приведенном выше примере кода (то есть ресурс не смог инициализировать) не подпадают под сценарий .. ресурс будет закрыт независимо от того, завершается ли оператор try нормально или внезапно . Это применимо только для инициализированных ресурсов успешно в попытке с оператором ресурсов и есть ошибка в блок try?

Неясно, на что вы ссылаетесь с помощью "ресурс будет закрыт независимо от того, завершается ли оператор try нормально или внезапно". Тем не менее, если попытка инициализации ресурса в спецификации ресурса выдает исключение, то нет, этот ресурс не закрыт, поскольку он не был инициализирован с ненулевым значением (ваша вторая точка маркера, которая является выдержкой из текста JLS) .

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

2) Если при инициализации ресурсов возникают исключения (например, пример), это попадет под неудачный сценарий инициализации. В этом случае, как мы сталкиваемся со сценарием исключения в операторе try-with-resources (который может произойти во время инициализации) вообще? Это исключения, выброшенные в то время как закрытие ресурса?

Оператор try-with-resources является составным оператором, охватывающим все, начиная с исходного ключевого слова try, вплоть до связанного блока, и включая любые предложения catch и и finally. Основное внимание уделяется правильной очистке в случае возникновения исключения изнутри блока try. Биты в спецификации о случаях, когда возникает исключение во время инициализации ресурса, могут быть поняты с точки зрения эквивалентности между оператором try-with-resources N и вложенным одиночным N операторы try-with-resources для ресурса.

Также обратите внимание, что JLS представляет перевод оператора try-with-resources в эквивалентный код с использованием традиционного try / catch / finally и явного закрытия ресурса. Это хороший ресурс для рассмотрения, если вы боретесь с семантикой try-with-resources.

0 голосов
/ 01 ноября 2018

try-with-resources является синтаксическим сахаром над старым синтаксисом, и написание его с использованием старого синтаксиса может помочь вам понять, что он делает:

Пример такого рода:

  try (AutoCloseable ac1 = ac1(); AutoCloseable ac2 = ac2()) {
    ac2.doWhatever();
  } catch (Exception e) { 
    fail(e);
  }

переписано так:

  AutoCloseable ac1 = null;
  try {
    ac1 = ac1();
    AutoCloseable ac2 = null;
    try {
      ac2 = ac2();
      ac2.doWhatever();
    } catch (Exception e) { 
      fail(e);
    } finally {
      if (ac2 != null) ac2.close();
    }
  } catch (Exception e) { 
    fail(e);
  } finally {
    if (ac1 != null) ac1.close();
  }

Компилятор, вероятно, оптимизирует код:

  • может быть только один блок finally, и он, вероятно, объединит два.
  • использовать некоторую синтетическую функцию для обработки того же улова.

Если вам интересно, эта презентация Э. Мандрикова объясняет, что делает компилятор и как это является головной болью для покрытия кода.

Как видите, в части инициализации может произойти сбой:

  • ac1 инициализация может завершиться неудачей, и в этом случае переменная будет null (значение по умолчанию).
  • ac2 инициализация может завершиться ошибкой, ac1 не будет нулевым.
  • ac1 и ac2 могут работать, и в этом случае только doWhatever() будет нести ответственность за сбой.

Если ac2 зависит от ac1 и отсутствует в списке ресурсов, например:

try (AutoCloseable ac2 = ac2(ac1())) {
  ...
}

Тогда сборка AutoCloseable по ac1() не закроется, если она не будет закрыта в ac2::close. А сборщик мусора не будет звонить ac1::close.

0 голосов
/ 01 ноября 2018

1) Да. Если ресурсы инициализированы успешно, и если у блока try есть исключение, ресурсы будут закрыты, как мы делаем это в блоке finally без попытки с ресурсом.

2) Документация гласит (немного изменено):

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

Как вы упомянули, исключение из try-with-resource во втором пункте будет из-за закрытия ресурсов.

...