Является ли Try-Catch более или менее дорогостоящим, чем Try-With-Resources
Вопрос
Я недавно начал возвращаться в Java и никогда не имел возможности использовать try-with-resources
. На первый взгляд это выглядит великолепно, поскольку он может сократить код, но под капотом это более или менее дорогостоящая операция, чем традиционная try-catch
? Я знаю, что try-catch
уже является дорогостоящей операцией, поэтому мое любопытство.
Я дал оба типа простой тест и не заметил большой разницы:
Примеры тестов
Тест с ресурсами
long startTime = System.currentTimeMillis();
ArrayList<String> list = null;
try (Scanner sc = new Scanner(new File("file.txt"))) {
list = new ArrayList();
while (sc.hasNext()) {
list.add(sc.next());
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
} finally {
long endTime = System.currentTimeMillis();
System.out.println("The program completed in " + (endTime - startTime) + " ms");
}
Традиционный пробный тест
long startTime = System.currentTimeMillis();
ArrayList<String> list = null;
Scanner sc = null;
try {
sc = new Scanner(new File("file.txt"));
list = new ArrayList();
while (sc.hasNext()) {
list.add(sc.next());
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
} finally {
sc.close();
long endTime = System.currentTimeMillis();
System.out.println("The program completed in " + (endTime - startTime) + " ms");
}
Результаты
Оба привели к времени 15-16 мс - никакой реальной заметной разницы вообще. Но, по общему признанию, это очень маленький тестовый пример.
Мой вопрос снова: под капотом try-with-resources
более или менее дорогим, чем традиционный try-catch
?
Ответы
Ответ 1
- try-catch - не дорогая часть. Выбрасывание исключения (создание stacktrace).
- "Дорого" выше означает "стоит несколько микросекунд".
- try-with-resources - это просто try-catch с правильным кодом, необходимым для надежного закрытия ресурса.
- Ваш код измерения не может ничего доказать из-за всех известных ошибок, связанных с попыткой измерить производительность в рамках оптимизации времени выполнения, такого как HotSpot. Вам нужно разогреться, повторить то же самое много раз и многое другое.
- Если ваш результат превышает 10 мс, то, очевидно, у вас не может быть проблемы с try-catch, которая может вообще наложить накладные расходы в течение нескольких микросекунд.
Ответ 2
Это яблоки и апельсины. Блок ARM (автоматическое управление ресурсами или try-with-resources) делает больше, чем старомодный блок try-catch-finally, который вы показываете. Это потому, что он генерирует код для обработки исключений, которые возникают при закрытии ресурсов с помощью механизма подавления (A связанный ответ обсуждает это в деталях.)
Если вы пишете новый код, используйте блок ARM. Его легче читать, поддерживать, и он делает больше. Если вы не работаете в тесно связанной среде (например, смарт-карте), эти преимущества, скорее всего, перевесят стоимость нескольких дополнительных байтовых кодов.
Ответ 3
Try-catch-finally и try-with-resources имеют по существу одну и ту же производительность, потому что под обложками они генерируют по существу один и тот же байт-код.
Однако ваша вторая версия (try..catch..finally) не совсем сформулирована правильно, поскольку она (теоретически) может привести к нежелательному NullPointerException
, когда вызывается sc.close()
. Если акт построения Scanner
вызывает исключение, то sc
не будет назначаться и будет null
.
Вы должны построить сканер вне try..finally
и изменить это:
Scanner sc = null;
try {
sc = new Scanner(new File("file.txt"));
...
в
Scanner sc = new Scanner(new File("file.txt"));
try {
...
В качестве альтернативы вы должны проверить, что sc != null
в предложении finally
перед вызовом sc.close()
. Это не будет необходимо, если вы создадите сканер вне try..finally, поэтому я бы порекомендовал вам сделать это.
Чтобы выполнить ту же работу, что и try-with-resources, вам также нужно поместить второй try..catch
вокруг sc.close()
с пустым блоком catch, чтобы игнорировать все исключения, которые были выбраны во время закрытия. Если вы это сделаете, я полагаю, вам не нужно так беспокоиться о нулевой проверке.