Сначала сформулируйте суть этой статьи:
-
Так называемый ресурс (ресурс) здесь относится к объекту, который должен быть закрыт после завершения программы Оператор try-with-resources обеспечивает закрытие каждого ресурса в конце оператора;
-
Используйте новый оператор try-with-resources в Java 7 вместо оператора try-finally для закрытия ресурсов, который не только более рационален, но и безопаснее;
-
Все классы, поддерживающие операторы try-with-resources, должны реализовывать
AutoCloseable
Аналогичным образом, наши пользовательские классы также могут реализовать этот интерфейс, чтобы помочь нам выполнить безопасное автоматическое освобождение ресурсов; -
В Java 9 были внесены улучшения в оператор try-with-resources: если у вас есть ресурс, который является окончательным или эквивалентен финальной переменной, вы можете использовать переменную в операторе try-with-resources, нет необходимости в операторе try-with. Оператор -resources Снова объявить новую переменную.
Вот несколько простых и практических примеров, демонстрирующих различные варианты использования оператора try-with-resources.
оператор try-finally перед Java 7
Перед эксплуатацией ресурсов, чтобы предотвратить невозможность закрытия ресурсов из-за исключений, поток ресурсов был закрыт с помощью оператора try-finally.
В этом есть два недостатка:
- уродливый код
- небезопасный
Например, описанный ниже метод чтения и записи файлов требует определения большого количества переменных, а также повторяющихся операций захвата исключений и закрытия.
public static void method1() {
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
FileReader fileReader = null;
BufferedReader bufferedReader = null;
File file = new File("try-with-resources-demo.txt");
try {
fileWriter = new FileWriter(file);
bufferedWriter = new BufferedWriter(fileWriter);
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
bufferedWriter.write("now is:" + LocalDateTime.now() + "\n\r");
bufferedWriter.write("availableProcessors are : " + Runtime.getRuntime().availableProcessors() + "\n\r");
bufferedWriter.write("totalMemory is : " + Runtime.getRuntime().totalMemory() + "\n\r");
bufferedWriter.write("maxMemory is : " + Runtime.getRuntime().maxMemory() + "\n\r");
bufferedWriter.write("freeMemory is : " + Runtime.getRuntime().freeMemory() + "\n\r");
bufferedWriter.flush();
StringBuffer readResult = new StringBuffer("");
String oneLine = null;
while (null != (oneLine = bufferedReader.readLine())) {
readResult.append(oneLine + "\n\r");
}
System.out.println(readResult.toString());
} catch (IOException ioe) {
//TODO log: IOException
ioe.printStackTrace();
} finally {
try {
if (null != fileReader)
fileReader.close();
} catch (IOException ioe) {
//TODO log: close stream has an IOException
ioe.printStackTrace();
}
try {
if (null != bufferedReader)
bufferedReader.close();
} catch (IOException ioe) {
//TODO log: close stream has an IOException
ioe.printStackTrace();
}
try {
if (null != fileWriter)
fileWriter.close();
} catch (IOException ioe) {
//TODO log: close stream has an IOException
ioe.printStackTrace();
}
try {
if (null != bufferedWriter)
bufferedWriter.close();
} catch (IOException ioe) {
//TODO log: close stream has an IOException
ioe.printStackTrace();
}
}
}
Такая программа явно неприемлема для друзей с чистотой кода.
оператор попытки с ресурсами
Использование оператора try-with-resources намного проще.
public static void method2() {
File file = new File("try-with-resources-demo.txt");
try (
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
) {
bufferedWriter.write("now is:" + LocalDateTime.now() + "\n\r");
bufferedWriter.write("availableProcessors are : " + Runtime.getRuntime().availableProcessors() + "\n\r");
bufferedWriter.write("totalMemory is : " + Runtime.getRuntime().totalMemory() + "\n\r");
bufferedWriter.write("maxMemory is : " + Runtime.getRuntime().maxMemory() + "\n\r");
bufferedWriter.write("freeMemory is : " + Runtime.getRuntime().freeMemory() + "\n\r");
bufferedWriter.flush();
StringBuffer readResult = new StringBuffer("");
String oneLine = null;
while (null != (oneLine = bufferedReader.readLine())) {
readResult.append(oneLine + "\n\r");
}
System.out.println(readResult.toString());
} catch (IOException ioe) {
//TODO log: IOException
ioe.printStackTrace();
}
}
Реализовать интерфейс AutoCloseable
Проследив исходный код, вы обнаружите, что классы, которые автоматически закрывают ресурсы с помощью оператора try-with-resources, реализуют интерфейс AutoCloseable.
Интерфейс AutoCloseable имеет только один параметр без параметров.close()
метод, ресурсы, объявленные с помощью оператора try-with-resources, если этот метод реализован, его можно вызвать до создания исключенияclose()
метод для выполнения операции закрытия ресурса.
Ниже приведен пример использования пула потоков для выполнения задач.ExecutorServiceAutoCloseable
, этот класс реализует интерфейс AutoCloseableclose()
метод, вы можете закрыть пул потоков после создания исключения, чтобы достичь цели высвобождения ресурсов потока.
package net.ijiangtao.tech.designskill.trywithresources;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* AutoCloseable Thread pool
*
* @author ijiangtao
* @create 2019-05-13 13:08
**/
public class ExecutorServiceAutoCloseable implements AutoCloseable {
private ExecutorService pool;
private int poolSize;
public ExecutorServiceAutoCloseable() {
poolSize = Runtime.getRuntime().availableProcessors();
pool = Executors.newFixedThreadPool(poolSize);
}
public void execute(Runnable runnable) {
if (pool.isShutdown())
throw new UnsupportedOperationException("pool isShutdown now");
pool.execute(runnable);
}
@Override
public void close() throws Exception {
System.out.println("auto close now !!!!!!!!!!! ");
pool.shutdown();
}
public static void main(String[] args) {
try (ExecutorServiceAutoCloseable executorServiceAutoCloseable = new ExecutorServiceAutoCloseable();) {
executorServiceAutoCloseable.execute(new Runnable() {
@Override
public void run() {
Integer.parseInt("test auto close");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Ниже приведен результат вывода, вы можете видеть, что перед выдачей исключения первое выполнениеclose()
метод закрытия ресурса.
auto close now !!!!!!!!!!!
Exception in thread "pool-1-thread-1" java.lang.NumberFormatException: For input string: "test auto close"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at net.ijiangtao.tech.designskill.trywithresources.ExecutorServiceAutoCloseable$1.run(ExecutorServiceAutoCloseable.java:39)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Цель этого состоит в том, что когда программа завершается из-за исключения, пул потоков не нужно закрывать явно, а можно закрыть автоматически, тем самым максимально быстро освобождая ресурсы потока и уменьшая потребление памяти.
Здесь следует отметить, что пул потоков закрывается в конце программы.Преимущество этого в том, что он занимает меньше памяти.Недостаток в том, что пул потоков должен создаваться заново каждый раз при выполнении программы, которая имеет определенный потребление производительности.
Так что все зависит от конкретной ситуации. Обычно, если программа запускается часто, потоки в пуле потоков резервируются и используются повторно, чтобы уменьшить потребление производительности, вызванное повторным созданием и уничтожением потоков. Однако, если программа не запускается снова через короткое время после запуска, пул потоков можно закрыть, чтобы освободить занятую память.
Конечно, вы также можете установить свою собственную стратегию управления потоками, задав количество основных потоков, максимальное количество потоков и время истечения срока действия.
Для конкретного использования, пожалуйста, обратитесь к этой статье:Используйте ThreadPoolExecutor для создания пула потоков.
Конечные переменные Java 9
В Java 9 синтаксис оператора try-with-resources был дополнительно упрощен.
Если у вас есть ресурс, который является окончательным или эквивалентен переменной final, вы можете использовать эту переменную в операторе try-with-resources без объявления новой переменной в операторе try-with-resources.
Написание на Java 7 и Java 8:
private static String readDataJava7(String message) throws IOException {
Reader reader = new StringReader(message);
BufferedReader bufferedReader = new BufferedReader(reader);
try (BufferedReader bufferedReader2 = bufferedReader) {
return bufferedReader2.readLine();
}
}
Написание, поддерживаемое Java 9:
private static String readDataJava9(String message) throws IOException {
Reader reader = new StringReader(message);
BufferedReader bufferedReader = new BufferedReader(reader);
try (bufferedReader) {
return bufferedReader.readLine();
}
}
Суммировать
Преимущества передачи оператора try-with-resources можно резюмировать следующим образом:
- оператор try-with-resources может привести к более лаконичному коду
- Оператор try-with-resources может сделать выпуск ресурсов более безопасным.
- Реализуйте интерфейс AutoCloseable самостоятельно и используйте оператор try-with-resources для обеспечения безопасного и краткого выпуска ресурсов.