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

时间:2018-07-24 12:59:31

标签: java try-with-resources

假设,我有一个返回Result类实例的方法:

public class Result {
    pubilc InputStream content;
    public long contentLength;
}

我想使用此InputStream安全地工作,但是显然,由于Result不会影响Closeable,所以我不能只写这样的东西:

try (Result result = getResult()) {
    ...
}

一种可能的解决方案是使Result Closeable:

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();
    }
}

我也考虑过这样的事情:

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

但是如果getResult()抛出异常,它将失败。

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

2 个答案:

答案 0 :(得分:3)

您可以创建工厂方法来创建Autocloseable包装器。

public Autocloseable autocloseable(Result result) {
    return new Autocloseable() {
        public void close() {
            result.content.close();
        }
    }
}

然后使用像这样的try-with-resources

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();
    }
}

被称为

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

答案 1 :(得分:2)

也许不是很好,但是很明显:

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

可以变成

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