Java中相当于Python的"with"的语法是什么?

5
Python 有一个很棒的功能:使用 "with" 语句。它可以用于全局更改,在语句内调用的所有代码都会受到影响。
例如,您可以定义一个名为 CapturePrintStatements 的类来捕获 "with" 中调用的所有 print 语句。
with CapturePrintStatements() as c:
    print 'Stuff Done'
print 'More Stuff Done'
assert c.get_text() == 'Stuff Done'

在Java中有对应的方法吗?
2个回答

10
try-with-resources是Java中的相应表示,可在Java 7及以上版本中使用。这使您有可能处理需要显式关闭但无需担心关闭的资源。例如:

Java7之前:

InputStream input = null;

try {
    input = new FileInputStream("myFile.txt");

} finally {
    if(input != null){
        input.close();
    }
}

Java 7及以上版本:

try(FileInputStream input = new FileInputStream("myFile.txt")) {
    // Do something with the InputStream
}

这是try-with-resources结构。当执行流程退出try块时,FileInputStream将会自动关闭。这是因为FileInputStream实现了AutoCloseable接口。


10

正如Mohammed所指出的,您可以使用try-with-resources。在这种情况下,您想要拥有自己的资源,这并不是很难做到。

创建一个可自动关闭类

首先,您的类应该实现AutoCloseable

public class CaptureOutput implements AutoCloseable {

构造此类时,您应该:

  • 存储旧的System.out,
  • 创建一个PrintStream来替换它(参见Java: PrintStream to String?),并且
  • 使用System.setOut()替换默认流。

下面是如何实现的:

    public CaptureOutput() {
        this.stream = new ByteArrayOutputStream();
        this.out = System.out;

        System.setOut(new PrintStream(stream));
    }

秘诀在于AutoCloseable.close()方法:您只需在那里撤消替换:

    public void close() throws Exception {
        System.setOut(this.out);
    }

最后,您需要一种检索内容的方法:

    public String getContent() {
        return this.stream.toString();
    }

使用try-with-resources

做到这一点,只需将CaptureOutput传递给try子句。例如下面的代码...

public static void main(String[] args) throws Exception {
    String content = null;

    System.out.println("This will be printed");

    try (CaptureOutput co = new CaptureOutput()) {
        System.out.println("EXAMPLE");

        content = co.getContent();
    }

    System.out.println("This will be printed, too.");

    System.out.println("The content of the string is " + content);
}

这将导致以下结果:

This will be printed
This will be printed, too.
The content of the string is EXAMPLE

作用域问题

请注意,我们在最后一行不调用 co.getContent()。这是不可能的,因为与 Python 不同,co 变量的作用域仅限于 try 代码块中。一旦 try 块结束,它就消失了[1]。这就是为什么我们从块内获取值。

不太优雅,是吧?一个解决方案可能是将 BAOS 提供给 CaptureOutput 构造函数:

    public CaptureOutput(ByteArrayOutputStream stream) {
        this.stream = stream;
        this.out = System.out;

        System.setOut(new PrintStream(this.stream));
    }

现在,我们稍后再使用流:

    public static void main(String[] args) throws Exception {
        System.out.println("This will be printed");

        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        try (CaptureOutput co = new CaptureOutput(stream)) {
            System.out.println("EXAMPLE");
        }

        System.out.println("This will be printed, too.");

        System.out.println("The content of the string is " + stream.toString());
    }

(此外,在try之前创建CaptureOutput变量是不可能的。这是有道理的: AutoCloseable对象应该在使用后被“关闭”。毕竟,关闭的文件有什么用呢?但我们的用例略有不同,因此我们必须依靠替代方法。)

完整的类

以下是完整的类:

  • CaptureOutput.java:

    import java.io.ByteArrayOutputStream;
    import java.io.PrintStream;
    
    public class CaptureOutput implements AutoCloseable {
    
        private ByteArrayOutputStream stream;
        private PrintStream out;
    
        public CaptureOutput(ByteArrayOutputStream stream) {
            this.stream = stream;
            this.out = System.out;
    
            System.setOut(new PrintStream(this.stream));
        }
    
        public CaptureOutput() {
            this(new ByteArrayOutputStream());
        }
    
        @Override
        public void close() throws Exception {
            System.setOut(this.out);
        }
    
        public String getContent() {
            return this.stream.toString();
        }
    
    }
    
  • Main.java

    import java.io.ByteArrayOutputStream;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
            System.out.println("This will be printed");
    
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
    
            try (CaptureOutput co = new CaptureOutput(stream)) {
                System.out.println("EXAMPLE");
            }
    
            System.out.println("This will be printed, too.");
    
            System.out.println("The content of the string is " + stream.toString());
        }
    
    }
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接