从Java 7开始,我们可以使用try-with-resources并自动关闭任何实现Autocloseable
接口的对象。 如果资源是 Autocloseable
。 一些类需要一些总结,但不是Autocloseable
。 这些主要是某些遗留框架中的旧类,仍然妨碍我们前进。 没有人再使用Struts了,但是仍然有足够多的旧框架潜伏在黑暗中,我们必须使用它们。 我最近有这种经验,而且我非常有动力,所以我创建了一个简单的AutoCloser
类。
我们可能有一个遗留类(在示例中,这是测试类的模拟内部类)
public class NotAutoclosable { public NotAutoclosable() { opened = true ; } public void dispose() { opened = false ; } }
顾名思义,它不是自动关闭的。 它没有实现Autocloseable
接口,并且没有close()
方法。 必须调用适当命名的方法dispose()
来处置它。 ( opened
的boolean
字段用于稍后在单元测试中进行检查,以断言AutoCloser
类的正确功能。)
该类的用法如下:
@Test void test() { final NotAutoclosable notAu; try ( final var s = AutoCloser.useResource( new NotAutoclosable()) .closeWith(sp -> sp.get().dispose())) { Assertions.assertTrue(opened); } Assertions.assertFalse(opened); }
我们使用内部类的构造函数创建资源,并定义将“关闭”资源的Consumer
。 该使用者将获得与变量s
存储的相同的Supplier
。
旁注:此函数参数必须是使用者,并且不能使用变量s
成为Runnable
,因为在将lambda表达式评估为lambda表达式时,不会初始化该变量。 当将要使用它时,它已经被定义了,但是对于Java编译器来说为时已晚,它并不那么信任程序员,通常情况下,它有充分的理由做到这一点。
AutoCloser
类如下:
public class AutoCloser<T> { private final T resource; private AutoCloser(T resource) { this .resource = resource; } public static <T> AutoCloser<T> useResource(T resource) { return new AutoCloser<>(resource); } public AutoClosableSupplier closeWith(Consumer<Supplier<T>> closer){ return new AutoClosableSupplier(closer); } public class AutoClosableSupplier implements Supplier<T>, AutoCloseable { private final Consumer<Supplier<T>> closer; private AutoClosableSupplier(Consumer<Supplier<T>> closer) { this .closer = closer; } @Override public T get() { return resource; } @Override public void close() { closer.accept( this ); } } }
之所以使用内部的AutoClosableSupplier
类,是因为我们不希望程序员意外忘记指定最终将关闭资源的lambda。
这真的没有什么严重的。 这只是一种编程风格,它类似于Go语言中的deferred
语句,将资源的关闭移到了资源的打开处。
翻译自: https://www.javacodegeeks.com/2019/05/box-old-objects-autoclosable.html