Рубрики
Без рубрики

Вступающий в силу Java Вторник! Предпочитаю пробовать с ресурсами

Погружение в девятую главу Эффективной Java. С тегами java, эффективный, дизайн, архитектура.

Эффективный обзор Java (Серия из 79 частей)

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

Существует множество ресурсов, которые по той или иной причине необходимо вручную закрыть после использования. Это часто достигается с помощью метода close для объекта. Мы, конечно, не хотим утекать ресурсы или оставлять предметы в наполовину обработанном состоянии. В этом случае мы можем рассмотреть возможность размещения метода close в блоке finally . Например:

static List getDbValues() {
  EntityManager em = getEntityManager();
  try {
    return em.createNativeQuery("SELECT * FROM myTable").getResultsList();
  } finally {
    em.close();
  }
}

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

static List getDbValues() {
  OutputStream output = getOutputStream();
  InputStream input = getInputstream();
  try {
    try {
      // do work
    } finally {
      input.close();
    }
  } finally {
    output.close();
  }
}

Это начинает становиться все более грубым и трудным для понимания. Я вообще правильно это сделал? Я не убежден. Это может быть легко испортить. Автор даже признает, что он годами путал этот шаблон в одной из своих книг, и никто этого не понимал. Даже при правильном коде есть тонкости с обработкой ошибок, которые обрабатываются не так хорошо, как могли бы. Исключения могут переопределять друг друга, и мы можем потерять ценную информацию в возникающих трассировках стека. Вы могли бы написать код, чтобы справиться с этим но это сложно и уродливо, поэтому никто так не писал.

Итак, в Java 7 мы получили лучший ответ – попробуйте с ресурсами. С помощью этой конструкции любой класс, реализующий Автоматически закрываемый может быть обработан Java. Таким образом, приведенный выше пример выглядит следующим образом:

try(InputStream input = new FileInputStream("file");
    OutputStream output = new FileOutputStream("other")) {
            // do work
}

Это намного проще. Он также обрабатывает намного больше, чем мы обрабатывали в нашем предыдущем примере. На самом деле код остается не таким. Приведенный выше код преобразуется компилятором в гораздо более подробный результат. Давайте взглянем:

InputStream input = new FileInputStream("file");
Throwable var2 = null;

try {
    OutputStream output = new FileOutputStream("other");
    Throwable var4 = null;

    try {
        //do work
    } catch (Throwable var27) {
        var4 = var27;
        throw var27;
    } finally {
        if (output != null) {
            if (var4 != null) {
                try {
                    output.close();
                } catch (Throwable var26) {
                    var4.addSuppressed(var26);
                }
            } else {
                output.close();
            }
        }

    }
} catch (Throwable var29) {
    var2 = var29;
    throw var29;
} finally {
    if (input != null) {
        if (var2 != null) {
            try {
                input.close();
            } catch (Throwable var25) {
                var2.addSuppressed(var25);
            }
        } else {
            input.close();
        }
    }

}

Ух ты! Это стало довольно напряженным. Но если вы проанализируете его, вы увидите, что он выполняет работу, на которую мы надеялись, при более полной обработке исключений.

Последняя мысль. В предыдущем посте Я упомянул инструмент Ломбок . Я очень думаю, что это хороший инструмент. Внутри мешка с трюками Ломбока есть аннотация @Очистка . Похоже, он сделает что-то очень похожее на описанное выше. Так что же отличает этих двоих? Хотя правильно, что они делают похожие вещи, они немного отличаются. Главное отличие заключается в том, что @Cleanup просто записывает комбинации try-finally, как мы делали выше, но не выполняет никакой магии, обрабатывая обработку исключений. Таким образом, в то время как @Cleanup обеспечивает нам безопасность блока finally, мы теряем специализированную обработку исключений.

Итак, вот оно у вас. Используйте “попробуй с ресурсами”. Это проще, чище, безопаснее, это действительно место, где я не вижу много недостатков.

Эффективный обзор Java (Серия из 79 частей)

Оригинал: “https://dev.to/kylec32/effective-java-tuesday-prefer-try-with-resources-2om9”