当资源位于不可关闭的包装器内时,Java尝试使用资源

当资源位于不可关闭的包装器内时,Java尝试使用资源,java,try-with-resources,Java,Try With Resources,假设有一个方法返回结果类的实例: public class Result { pubilc InputStream content; public long contentLength; } 我想安全地使用这个InputStream,但很明显,由于结果不可关闭,我不能这样写: try (Result result = getResult()) { ... } Result result = getResult(); try (InputStream stream =

假设有一个方法返回结果类的实例:

public class Result {
    pubilc InputStream content;
    public long contentLength;
}
我想安全地使用这个InputStream,但很明显,由于结果不可关闭,我不能这样写:

try (Result result = getResult()) {
    ...
}
Result result = getResult();
try (InputStream stream = result.content) {
   ...
}
可能的解决方案之一是使结果接近:

public class Result implements Closeable {
    public InputStream content;
    public long contentLength;

    @Override
    public void close() throws IOException {
        content.close();
    }
}
...
// this should work now
try (Result result = getResult()) {
    ...
} catch (IOException) {
    ...
}
但如果我不能修改结果(或不想修改),该怎么办

另一种方法是手动调用close(),但它有点笨重:

Result result = null;
try {
    result = getResult();
    ...
} catch (...) {
    ...
} finally {
    if (result != null) {
        result.content.close();
    }
}
我也想到了这样的事情:

try (Result result = getResult()) {
    ...
}
Result result = getResult();
try (InputStream stream = result.content) {
   ...
}
但如果getResult()引发异常,则它将失败


所以我的问题是:在这种情况下还有其他选择吗?

您可以创建一个工厂方法来创建一个可自动关闭的包装器

public Autocloseable autocloseable(Result result) {
    return new Autocloseable() {
        public void close() {
            result.content.close();
        }
    }
}
然后使用像这样的资源进行尝试

Result result = getResult();
try (Autocloseable ac = autocloseable(result)) {
    doStuffWith(result);
}
当然,也可能是过度工程化

class AutoclosingWrapper<T> implements Autocloseable {
    private T object;
    private Function<T, Autocloseable> autocloseable;

    public AutoclosingWrapper(Supplier<T> c, Function<T, Autocloseable> a) {
        this(c.get(), a);
    }
    public AutoclosingWrapper(T t, Function<T, Autocloseable> a) {
        object = t;
        autocloseable = a;
    }
    public T getObject() {
        return object;
    }
    public void close() {
        autocloseable.apply(object).close();
    }
}
类AutoclosingWrapper实现自动关闭{ 私人T对象; 专用功能自动关闭; 公共自动关闭包装器(供应商c,功能a){ 这(c.get(),a); } 公共自动关闭包装器(T,函数a){ 对象=t; 自动关闭=a; } 公共T getObject(){ 返回对象; } 公众假期结束(){ 自动关闭。应用(对象)。关闭(); } } 这叫做

try (AutoclosingWrapper<Result> wrapper = new AutoclosingWrapper(this::getResult, r -> r.content)) {
    doStuffWith(wrapper.getObject());
}
try(AutoclosingWrapper=newautoclosingwrapper(this::getResult,r->r.content)){
doStuffWith(wrapper.getObject());
}

您可以创建一个工厂方法来创建一个可自动关闭的包装器

public Autocloseable autocloseable(Result result) {
    return new Autocloseable() {
        public void close() {
            result.content.close();
        }
    }
}
然后使用像这样的资源进行尝试

Result result = getResult();
try (Autocloseable ac = autocloseable(result)) {
    doStuffWith(result);
}
当然,也可能是过度工程化

class AutoclosingWrapper<T> implements Autocloseable {
    private T object;
    private Function<T, Autocloseable> autocloseable;

    public AutoclosingWrapper(Supplier<T> c, Function<T, Autocloseable> a) {
        this(c.get(), a);
    }
    public AutoclosingWrapper(T t, Function<T, Autocloseable> a) {
        object = t;
        autocloseable = a;
    }
    public T getObject() {
        return object;
    }
    public void close() {
        autocloseable.apply(object).close();
    }
}
类AutoclosingWrapper实现自动关闭{ 私人T对象; 专用功能自动关闭; 公共自动关闭包装器(供应商c,功能a){ 这(c.get(),a); } 公共自动关闭包装器(T,函数a){ 对象=t; 自动关闭=a; } 公共T getObject(){ 返回对象; } 公众假期结束(){ 自动关闭。应用(对象)。关闭(); } } 这叫做

try (AutoclosingWrapper<Result> wrapper = new AutoclosingWrapper(this::getResult, r -> r.content)) {
    doStuffWith(wrapper.getObject());
}
try(AutoclosingWrapper=newautoclosingwrapper(this::getResult,r->r.content)){
doStuffWith(wrapper.getObject());
}

也许不太好,但很明显:

Result result = getResult();
try (InputStream content = result.content) {
    ...
}
可以变成

Result result;
try (InputStream content = (result = getResult()).content) {
    ...
}

也许不太好,但很明显:

Result result = getResult();
try (InputStream content = result.content) {
    ...
}
可以变成

Result result;
try (InputStream content = (result = getResult()).content) {
    ...
}

但如果我不能修改结果(或不想修改),该怎么办?然后,您将无法使其自动关闭,并且尝试使用资源不适合您。理论上,您可以包装iputstream以在出现错误时关闭底层流并重新抛出(或吞下)异常,请注意,如果
getResult()
t出现异常,您没有
Result
对象,因此您没有要关闭的对象。最简单和正确的解决方案是使该类可关闭。但如果我无法修改结果(或不想),该怎么办?然后,您将无法使其自动关闭,并且尝试使用资源不适合您。理论上,您可以包装iputstream以在出现错误时关闭底层流并重新抛出(或吞下)异常,请注意,如果
getResult()
t出现异常,你没有
Result
对象,因此你没有什么可关闭的。最简单和正确的解决方法是使这个类可关闭。@Antoniosss你是对的,复制用于编辑,将我的杯子扔到桌子上,然后取了一些纸巾。也许更值得一提。@Antoniossss你说得对,抄写编辑,把我的杯子扔到桌子上,然后拿了一些纸巾。也许更值得一提。