Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
236 views
in Technique[技术] by (71.8m points)

java - Correctly closing resources in constructor and close method in case of error

Given an AutoCloseable class MyClass that creates multiple resources of type SomeResource in its constructor. SomeResource also implements AutoCloseable and both its constructor and its close method may throw an IOException. How do I best make sure that:

  • a) the constructor correctly closes all opened resources when a failure occurs during construction
  • b) the close method correctly closes all resources in case of failure while closing one of the resources.

Here is the example class:

public class MyClass implements AutoCloseable {

    private final SomeResource resource1;
    private final SomeResource resource2;
    private final SomeResource resource3;

    MyClass() throws IOException {
        resource1 = new SomeResource();
        resource2 = new SomeResource();
        resource3 = new SomeResource();
    }

    @Override public void close() throws IOException {
        resource1.close();
        resource2.close();
        resource3.close();
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

a) The constructor cannot use try-with-resources nor try-finally because the resources shall not be closed in case the resources can be created successfully. Instead the creation of a resource should be followed by a try-catch block that makes sure the resource is closed in case of any error that follows its creation. Inside the catch block the exception has to be rethrown so it is not lost.

b) the close method can use a try-with-resource block to make sure all resources are closed

public class MyClass implements AutoCloseable {

  private final SomeResource resource1;
  private final SomeResource resource2;
  private final SomeResource resource3;

  MyClass() throws IOException {
    resource1 = new SomeResource();
    try {
      resource2 = new SomeResource();
      try {
        resource3 = new SomeResource();
      } catch (IOException | RuntimeException e) {
        closeIgnoreException(resource2);
        throw e;
      }
    } catch (IOException | RuntimeException e) {
      closeIgnoreException(resource1);
      throw e;
    }
  }

  private static void closeIgnoreException(AutoCloseable autoCloseable) {
    try { autoCloseable.close(); } catch (Exception ignore) {}
  }

  @Override
  public void close() throws IOException {
    try (resource1;
        resource2;
        resource3) {}
  }
}

Prior to Java 9 the try-with-resources statement accepted no references. Therefore the close method had to be realized in the following way:

  public void close() throws IOException {
    try (SomeResource r1 = resource1;
        SomeResource r2 = resource2;
        SomeResource r3 = resource3) {}
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...