Есть несколько подходов.
- Используйте идиому Execute Around .Измените интерфейс, чтобы упростить реализацию клиента и устранить проблему.
- Игнорировать проблему.Звучит глупо, но, как правило, это происходит при переносе с помощью декораторов потоков ввода-вывода.
- Оберните внутри прокси
AutoCloseable
и поместите это в свой try-with-resource. - Запишитеэквивалент использования try-with-resource try-catch и try-finally.(Я бы не стал - противным.)
- Напишите модифицированный try-with-resource как функцию библиотеки.Этот код станет клиентом Execute Around.
- Напишите исключение, обрабатывающее стиль старой школы, с помощью try-catch и try-finally.
Редактировать: Я подумал, что вернусь к ответу, добавив пример кода для забавы.
Выполнение вокруг идиомы
Простое и лучшее решение.К сожалению, библиотека Java не использует это много (AccessController.doPrivileged
- большое исключение), и соглашения не очень хорошо установлены.Как всегда, проверенные исключения Java без поддержки функций усложняют ситуацию.Мы не можем использовать java.util.function
и вынуждены изобретать собственные функциональные интерфейсы.
// Like Consumer, but with an exception.
interface Use<R, EXC extends Exception> {
void use(R resource) throws EXC;
}
public static void withThing(String name, Use<InputStream,IOException> use) throws IOException {
try (InputStream in = new FileInputStream(name)) {
use.use(in);
}
}
Красиво и просто.Не нужно беспокоиться о том, что клиентский код портит обработку ресурсов, поскольку он этого не делает.Хорошо.
Модифицированный try-with-resource как функция библиотеки, реализованная в виде прокси AutoCloseable
в try-with-resource
Это будет ужасно,Нам нужно передать получение, освобождение и инициализацию как лямбды.Создание ресурса непосредственно в этом методе открывает небольшое окно, где непредвиденное исключение может привести к утечке.
public static InputStream newThing(String name) throws IOException {
return returnResource(
() -> new FileInputStream(name),
InputStream::close,
in -> {
int ignore = in.read(); // some work
}
);
}
Общая реализация returnResource
будет выглядеть следующим образом.Хак, потому что try-with-resource не поддерживает такого рода вещи, а библиотека Java не поддерживает хорошо проверенные исключения.Примечание ограничено одним исключением (вы можете использовать непроверенное исключение для не отмеченных исключений).
interface Acquire<R, EXC extends Exception> {
R acquire() throws EXC;
}
// Effectively the same as Use, but different.
interface Release<R, EXC extends Exception> {
void release(R resource) throws EXC;
}
public static <R, EXC extends Exception> R returnResource(
Acquire<R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize
) throws EXC {
try (var adapter = new AutoCloseable() { // anonymous classes still define type
private R resource = acquire.acquire();
R get() {
return resource;
}
void success() {
resource = null;;
}
public void close() throws EXC {
if (resource != null) {
release.release(resource);
}
}
}) {
R resource = adapter.get();
initialize.use(resource);
adapter.success();
return resource;
}
}
Возможно, это будет чище, если мы отделим аргумент, с которым мы строим ресурс, от конструкции ресурса.
public static InputStream newThing(String name) throws IOException {
return returnResource(
name,
FileInputStream::new,
InputStream::close,
in -> {
int ignore = in.read(); // some work
}
);
}
// Like Function, but with a more descriptive name for a functional interface.
interface AcquireFrom<T, R, EXC extends Exception> {
R acquire(T t) throws EXC;
}
public static <T, R, EXC extends Exception> R returnResource(
T t, AcquireFrom<T, R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize
) throws EXC {
return returnResource(() -> acquire.acquire(t), release, initialize);
}
Итак, подытожим следующие вещи:
- Передача владения ресурсами.Держите его локальным.
java.util.function
не поддерживает проверенные исключения. - Библиотека Java не поддерживает Execute Around.
AutoCloseable::close
, объявляя, что она выдает Exception
вместо того, чтобы быть параметром типа типа. - Проверенные исключения без типов сумм.
- Синтаксис языка Java в целом.