задний план
Оператор try-finally должен делать это. Студенты Java не знакомы с этим, каждый раз, когда мы закроем наш спрос на ресурсы, мы будем использовать это для оператора try-finally, например, когда мы используем блокировку, будет ли локальная или реентерабельная блокировка распределенной блокировкой. аналогичную структуре кода ниже, мы, наконец, разблокируем внутреннюю часть, используемую для принудительной разблокировки:
Lock lock = new ReentrantLock();
lock.lock();
try{
// doSometing
}finally {
lock.unlock();
}
Или, когда мы используем файловый поток java для чтения или записи файлов, мы также принудительно закроем файловый поток, чтобы предотвратить утечку ресурсов.
InputStream inputStream = new FileInputStream("file");
try {
System.out.println(inputStream.read(new byte[4]));
}finally {
inputStream.close();
}
На самом деле, на первый взгляд, с этим способом записи не должно быть проблем, но если у нас есть несколько ресурсов, которые нужно закрыть, как нам это написать? Наиболее распространена следующая запись:
InputStream inputStream = new FileInputStream("file");
OutputStream outStream = new FileOutputStream("file1");
try {
System.out.println(inputStream.read(new byte[4]));
outStream.write(new byte[4]);
}finally {
inputStream.close();
outStream.close();
}
Мы определяем два ресурса снаружи, а затем последовательно закрываем два ресурса, наконец.Этот метод написания подобен этому, когда я впервые закрыл файловый поток и пул соединений с базой данных, когда впервые написал java.Teaching, так что же в этом не так? На самом деле проблема заключается в том, что если во время inputStream.close выдается исключение, то outStream.close() не будет выполняться, что, очевидно, не является тем результатом, который нам нужен, поэтому он заменяется на следующий метод множественной вложенности.
InputStream inputStream = new FileInputStream("file");
try {
System.out.println(inputStream.read(new byte[4]));
try{
OutputStream outStream = new FileOutputStream("file1");
outStream.write(new byte[4]);
}finally {
outStream.close();
}
}finally {
inputStream.close();
}
Таким образом, даже если outStream.close() выдает исключение, мы все равно выполним inputStream.close(), потому что они находятся в разных блоках finally Это действительно решает нашу проблему, но есть две нерешенные проблемы:
- Первый вопрос, который возникает: если у нас есть более двух ресурсов, скажем, десять ресурсов, нужно ли нам писать десять вложенных операторов? Могу ли я увидеть этот код после его написания?
- Второй вопрос, если у нас есть исключение в попытке, а затем в конечном итоге наблюдается исключение, он приведет к тому, что наложение исключений, что приведет к тому, что исключение, наконец, перезаписать исключение попробовать.
public class CloseTest {
public void close(){
throw new RuntimeException("close");
}
public static void main(String[] args) {
CloseTest closeTest = new CloseTest();
try{
throw new RuntimeException("doSomething");
}finally {
closeTest.close();
}
}
}
输出结果:Exception in thread "main" java.lang.RuntimeException: close
В приведенном выше коде мы ожидаем, что будет выдано исключение doSomething, но фактический результат данных — это близкое исключение, которое не соответствует нашим ожиданиям.
try-with-resources
Мы представили две проблемы выше, поэтому оператор try-with-resources был введен в java7, пока наши ресурсы реализованыAutoCloseable
Этот интерфейс, затем мы можем использовать этот оператор, наш предыдущий файловый поток реализовал этот интерфейс, поэтому мы можем использовать его напрямую:
try(InputStream inputStream = new FileInputStream("file");
OutputStream outStream = new FileOutputStream("file1")) {
System.out.println(inputStream.read(new byte[4]));
outStream.write(new byte[4]);
}
Все наши определения ресурсов определены в скобках после попытки Таким образом, мы можем решить проблемы, упомянутые выше:
- Прежде всего, по первому вопросу, таким образом, код очень чистый, независимо от того, сколько у вас ресурсов, вы можете сделать это очень лаконично.
- Вторую проблему покрытия исключений мы можем посмотреть на опыте, переписав код следующим образом:
public class CloseTest implements AutoCloseable {
@Override
public void close(){
System.out.println("close");
throw new RuntimeException("close");
}
public static void main(String[] args) {
try(CloseTest closeTest = new CloseTest();
CloseTest closeTest1 = new CloseTest();){
throw new RuntimeException("Something");
}
}
}
输出结果为:
close
close
Exception in thread "main" java.lang.RuntimeException: Something
at fudao.CloseTest.main(CloseTest.java:33)
Suppressed: java.lang.RuntimeException: close
at fudao.CloseTest.close(CloseTest.java:26)
at fudao.CloseTest.main(CloseTest.java:34)
Suppressed: java.lang.RuntimeException: close
at fudao.CloseTest.close(CloseTest.java:26)
at fudao.CloseTest.main(CloseTest.java:34)
Мы определяем два CloseTests в коде, чтобы проверить, повлияет ли предыдущее исключение закрытия на второе.В то же время в блоках закрытия и попытки выбрасываются разные исключения.Вы можете увидеть наши результаты и вывести два закрытия, Докажите, что хотя близко выдает исключение, выполняются оба закрытия. Затем выведите исключение doSomething, вы можете обнаружить, что то, что мы выводим здесь, — это исключение, созданное в нашем блоке try, и исключение, которое мы закрываем, записывается в стек исключений в виде Подавлено, Таким образом, мы можем иметь оба исключения , запишите это.
принцип попытки с ресурсами
Оператор try-with-resources на самом деле является синтаксическим сахаром, и после компиляции он возвращается во вложенный режим, о котором мы начали говорить:
Можно обнаружить, что после компиляции try-with-resources он принимает режим вложенности, но он немного отличается от предыдущего вложения: при закрытии он использует catch для перехвата исключения, а затем добавляет его в наш реальный исключение Общая логика немного сложнее, чем наша предыдущая вложенность.
Суммировать
Когда мы закрываем ресурсы, мы рекомендуем сначала использовать оператор try-with-resources, но здесь следует отметить, что многие ресурсы на самом деле не реализуют интерфейс AutoCloseable. Например, наша первоначальная блокировка не реализовывала этот интерфейс. время, если мы хотим использовать эту функцию, мы можем инкапсулировать Lock комбинированным способом для достижения нашей цели.
Если вы считаете, что эта статья полезна для вас, то ваше внимание и пересылка - самая большая поддержка для меня, O(∩_∩)O: