Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在一个try语句中打开多个资源是否不可靠?为什么?_Java_Try With Resources - Fatal编程技术网

Java 在一个try语句中打开多个资源是否不可靠?为什么?

Java 在一个try语句中打开多个资源是否不可靠?为什么?,java,try-with-resources,Java,Try With Resources,该计划: import java.util.*; public class Main { static Set<String> openResources = new TreeSet<>(); static class MyResource implements AutoCloseable { boolean close; MyResource encapsulatedResource; String

该计划:

import java.util.*;

public class Main {

    static Set<String> openResources = new TreeSet<>();

    static class MyResource implements AutoCloseable {

        boolean close;
        MyResource encapsulatedResource;
        String name;

        MyResource(String id, boolean exceptionOnCreate, boolean exceptionOnClose, MyResource encapsulatedResource) {
            this.close = exceptionOnClose;
            this.encapsulatedResource = encapsulatedResource;
            this.name = id;
            if (exceptionOnCreate) {
                throw new RuntimeException("Exception when creating " + id);
            }
            openResources.add(id);
            System.out.println(name + " is now open");
        }

        @Override
        public void close() {
            if (close) {
                throw new RuntimeException("Exception when closing " + name);
            }
            if (encapsulatedResource != null) {
                encapsulatedResource.close();
            }
            openResources.remove(name);
            System.out.println(name + " was successfully closed");
        }

    }

    public static void main(String[] args) {
        try (AutoCloseable resource1 = new MyResource("resource1", false, false, null);
                MyResource resource2 = new MyResource("resource2", false, true, null);
                AutoCloseable resource3 = new MyResource("resource3", false, false, resource2);
                AutoCloseable resource4 = new MyResource("resource4", true, false, null);) {
            System.out.println("main program");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("openResources: " + openResources);
    }
}
我希望在使用try-with-resources时,所有资源都已正确关闭,并且不会有任何泄漏。然而,在这里,资源2和资源3被泄漏了。为什么?我不能依赖这种语法吗?

参考资料2和3“泄漏”了,因为您定义异常的方式不同。由于资源4在创建时抛出异常,因此创建的资源将被关闭。资源3将尝试关闭,但由于它实际上正在尝试关闭资源2,因此资源3将引发异常(注意:此异常被抑制,因为它是在try部分中为原始异常提供服务时引发的)。关闭资源2还将导致抑制的异常,使资源1只剩下关闭的资源。

根据:

如果初始化资源的一次自动关闭突然完成 因为V值的抛出,以及所有其他自动关闭 初始化的资源正常完成,然后使用资源重试 语句由于抛出值V而突然完成

所以,这就是设计。引入try-with-resources的原因是为了减少开发人员的任务并自行处理资源处理。就可靠性而言,即使是旧的代码方式也会导致相同的资源泄漏。让我们试着用下面JAVA文档中提到的方法翻译代码:

让我们通过重新修改您的代码,并用在try中创建资源的旧方法编写代码,并最终完成,来尝试理解这一点

public class Main {

    static Set<String> openResources = new TreeSet<>();

    static class MyResource implements AutoCloseable {

        boolean close;
        MyResource encapsulatedResource;
        String name;

        MyResource(String id, boolean exceptionOnCreate, boolean exceptionOnClose, MyResource encapsulatedResource) {
            this.close = exceptionOnClose;
            this.encapsulatedResource = encapsulatedResource;
            this.name = id;
            if (exceptionOnCreate) {
                throw new RuntimeException("Exception when creating " + id);
            }
            openResources.add(id);
            System.out.println(name + " is now open");
        }

        @Override
        public void close() {
            if (close) {
                throw new RuntimeException("Exception when closing " + name);
            }
            if (encapsulatedResource != null) {
                encapsulatedResource.close();
            }
            openResources.remove(name);
            System.out.println(name + " was successfully closed");
        }

    }

    public static void main(String[] args) {
        AutoCloseable resource1 = null, resource3 = null, resource4 = null;
        MyResource resource2 = null;
        try {
            resource1 = new MyResource("resource1", false, false, null);
            resource2 = new MyResource("resource2", false, true, null);
            resource3 = new MyResource("resource3", false, false, resource2);
            resource4 = new MyResource("resource4", true, false, null);
            System.out.println("main program");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                resource1.close();
                resource2.close();
                resource3.close();
                resource4.close();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        System.out.println("openResources: " + openResources);
    }
}
如您所见,资源2和资源3是泄漏的资源 关闭资源2会导致异常,从而阻止关闭 资源3

类似地,对于try with resources,它希望在关闭时不会抛出异常,如果抛出异常,资源的关闭将在该时间点终止

这并不意味着try-with-resources不可靠或过时 资源处理更好。这只是意味着可关闭的 资源工作不正常,应已关闭或至少关闭 应该已经处理了异常,以便剩余的资源可以关闭 继续


希望这能有所帮助。

这与try-catch的“可靠性”无关,而与您连接资源的方式以及它们抛出异常的事实有关。试图关闭封装的resource2时,关闭resource3将引发异常。关闭resource2将引发异常。是的,您创建的示例确实存在上述缺陷。您已经发布了翻译,但您的代码不是等效的。@SotiriosDelimanolis感谢您的评论。我已经发布了JAVA文档所说的内容,但是如果您觉得它不同,请分享上述代码的等效内容。除此之外,如果ResourceSpecification声明了n>1个资源,那么ResourceSpecification_____________________________________,以相同的顺序(try-catch-finally语句本身就是try-with-resources语句)。每个
close()
调用都包装在一个
null
检查和它自己的
try-catch
语句中。它对所有资源调用
close
。在您的代码中,它将在第一次调用失败后停止。@SotiriosDelimanolis根据JAVA文档:如果一个初始化资源的自动关闭由于抛出值V而突然完成,而所有其他初始化资源的自动关闭正常完成,然后try with resources语句突然完成,因为抛出了值V。这导致了所有关闭都在一个try-catch-only中的情况。它特别指出[…]和所有其他自动关闭[…]。例如,如果第一个关闭失败,您的代码不会执行所有其他关闭。这句话的意思是,如果其中只有一个失败,那么相应的异常就是try with resources语句抛出的异常。如果不止一个抛出一个异常,那么就会应用整个被抑制的异常行为。
public class Main {

    static Set<String> openResources = new TreeSet<>();

    static class MyResource implements AutoCloseable {

        boolean close;
        MyResource encapsulatedResource;
        String name;

        MyResource(String id, boolean exceptionOnCreate, boolean exceptionOnClose, MyResource encapsulatedResource) {
            this.close = exceptionOnClose;
            this.encapsulatedResource = encapsulatedResource;
            this.name = id;
            if (exceptionOnCreate) {
                throw new RuntimeException("Exception when creating " + id);
            }
            openResources.add(id);
            System.out.println(name + " is now open");
        }

        @Override
        public void close() {
            if (close) {
                throw new RuntimeException("Exception when closing " + name);
            }
            if (encapsulatedResource != null) {
                encapsulatedResource.close();
            }
            openResources.remove(name);
            System.out.println(name + " was successfully closed");
        }

    }

    public static void main(String[] args) {
        AutoCloseable resource1 = null, resource3 = null, resource4 = null;
        MyResource resource2 = null;
        try {
            resource1 = new MyResource("resource1", false, false, null);
            resource2 = new MyResource("resource2", false, true, null);
            resource3 = new MyResource("resource3", false, false, resource2);
            resource4 = new MyResource("resource4", true, false, null);
            System.out.println("main program");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                resource1.close();
                resource2.close();
                resource3.close();
                resource4.close();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        System.out.println("openResources: " + openResources);
    }
}
resource1 is now open
resource2 is now open
resource3 is now open
Exception when creating resource4
resource1 was successfully closed
Exception when closing resource2
openResources: [resource2, resource3]