【问题标题】:Java equivalent to python's "with"Java相当于python的“with”
【发布时间】:2016-01-31 16:32:22
【问题描述】:

Python 有一个很好的特性:“with”语句。这对于进行影响语句中调用的所有代码的全局更改很有用。

例如您可以定义一个类 CapturePrintStatements 来捕获在“with”中调用的所有打印语句

with CapturePrintStatements() as c:
    print 'Stuff Done'
print 'More Stuff Done'
assert c.get_text() == 'Stuff Done'

Java 中是否有等价物?

【问题讨论】:

    标签: java python with-statement


    【解决方案1】:

    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 接口。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-13
        • 2018-06-15
        • 2011-04-26
        • 1970-01-01
        • 1970-01-01
        • 2011-05-29
        • 1970-01-01
        相关资源
        最近更新 更多