Я видел два способа приобретения и использования ресурсов. Либо:
Resource resource = getResource();
try { /* do something with resource */ }
finally { resource.close(); }
или же:
Resource resource = null;
try { resource = getResource(); /* do something with resource */ }
finally { if (resource != null) resource.close(); }
Мне было интересно, какой стиль предпочтительнее. Первый позволяет избежать условия if, а второй (я полагаю) обрабатывает случай прерывания потока сразу после назначения, но до входа в блок try. Какие еще плюсы и минусы есть у этих стилей друг перед другом? Какой из них я предпочитаю использовать?





Если getResource () вызывает исключение, тогда ресурс будет нулевым, getResource () ничего не возвращает в случае исключения. Итак, пока getResource () может генерировать исключение, всегда проверяйте значение null перед вызовом resource.close (). Я считаю, что лучший способ организовать этот код - поместить все в блок try; проясните, что getResource () генерирует исключения.
В аналогичном коде, где, скажем, происходит захват и освобождение блокировки, сбой в получении приведет к несогласованному освобождению.
В C# просто используйте оператор using:
using (Resource resource = GetResource())
{
/* Do something */
}
Это идиоматический способ очистки ресурсов, основанный на использовании соответствующего ресурса, реализующего интерфейс IDisposable. (В Java теперь есть аналогичный оператор try-with-resources для ресурсов, реализующих AutoCloseable.)
В Java нет риска прерывания потока между назначением и входом в блок try - прерывания происходят только во время ожидания и ожидания. Обновлено: Я не могу найти это в спецификации, что несколько беспокоит. Хм.
Спасибо. Ключевое слово using в C# великолепно, но иногда его нельзя использовать (например, с типом, который не реализует IDisposable, или когда Dispose () следует вызывать условно). Что касается Java, у меня вообще нет опыта с такими проблемами, но нельзя ли прерывать поток?
они могут быть прерваны (безопасно), если вы напишете код, позволяющий это, на самом деле происходит то, что потоки могут получать сигнал о том, что им нужно прервать, и в коде потока вы решаете, как остановить текущую выполняемую работу
Да, но, по крайней мере, они не будут прерваны пост-назначением, предварительным вводом-попыткой-блоком. Это важный момент :)
Могу я спросить, как вы знаете, что они не будут прерваны между заданием и попыткой?
@Hosam: Как я уже сказал, мне еще не удалось найти его в спецификации, но обратите внимание, что InterruptedException - это исключение проверил, поэтому его нельзя просто выбросить куда-нибудь. Я считаю, что задокументировано, что где-то будет выбрасываться только во время операций блокировки (ожидание / спящий режим / ввод-вывод и т. д.).
Спасибо, Джон. Вы как всегда помогаете.
@Alex: Честно говоря, я не думаю, что это необходимо. Я не вижу никаких признаков того, что кто-то был сбит с толку за более чем 10 лет с момента публикации этого ответа. ОП уже понял это (согласно первому комментарию).
@Alex: Я отредактирую его - но вы вполне можете найти множество ответов на вопросы о тегах C#, которые предполагают более чем двухдневный опыт работы с C#. (Многие будут говорить о лямбда-выражениях, не уточняя, что это означает, в качестве примера.) Я думаю, что читателям разумно искать любые термины, с которыми они не знакомы - в данном случае «оператор использования» - если только определение термина не является цель вопроса.
первый предпочтительнее
Однако с первой версией этого делать не нужно - если возникнет исключение, вы не дойдете до блока finally.