• Functional Programming in Java venkat(12) Working with Resources


    Functional Programming in Java venkat(12): Working with Resources

    这里是记录学习这本书 Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions 的读书笔记,如有侵权,请联系删除。

    Cleaning Up Resources

    处理外部资源的时候,不能只依赖于JVM,需要我们自己动手。

    比如 connect to databases, open files and sockets, or use native resources.

    Since the finalizer was rarely
    invoked, it led to external resource clogging and the resulting failure.

    由于finalizer很少被调用 导致外部资源堵塞,从而导致失败。

    Execute Around Method

    当一对动作必须一起进行时(如文件打开/关闭),你可以使用一个HigherOrderFunction,它将这些动作包裹在传入的函数中。

    When a pair of actions have to be taken together (such as file open/close), you can use a HigherOrderFunction that wraps the actions around the function that is passed in.

    关闭文件close代码可以运行,不管是否存在异常,但是smelly。

    We need to ensure the call to close() happens whether or not there’s an
    exception. To achieve this we can wrap the call in a finally block.

     public static void main(final String[] args) throws IOException {
        final FileWriterExample writerExample = 
          new FileWriterExample("peekaboo.txt");
        try {
          writerExample.writeStuff("peek-a-boo");            
        } finally {
          writerExample.close();      
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    自动资源管理 automatic resource management (ARM)

    ARM can reduce the verbosity in the previous example. Rather than using
    both the try and finally blocks, we can use a special form of the try block with
    a resource attached to it. Then the Java compiler takes care of automatically
    inserting the finally block and the call to the close() method.

    使用ARM的代码,专门用来处理上述冗余: 只用try,不用finally结构。然后,Java编译器会自动插入finally块和对close()方法的调用。

      public static void main(final String[] args) throws IOException {
        try(final FileWriterARM writerARM = new FileWriterARM("peekaboo.txt")) {
          writerARM.writeStuff("peek-a-boo");
    	  
          System.out.println("done with the resource...");
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    需要实现接口AutoCloseable 的close方法

    import java.io.FileWriter;
    import java.io.IOException;
    import java.lang.AutoCloseable;
    
    public class FileWriterARM implements AutoCloseable {
      private final FileWriter writer;
      
      public FileWriterARM(final String fileName) throws IOException {
        writer = new FileWriter(fileName);
      }
      
      public void writeStuff(final String message) throws IOException {
        writer.write(message);
      }
    
      public void close() throws IOException {
        System.out.println("close called automatically...");
        writer.close();
      }
    
      //...
    
      public static void main(final String[] args) throws IOException {
        try(final FileWriterARM writerARM = new FileWriterARM("peekaboo.txt")) {
          writerARM.writeStuff("peek-a-boo");
    	  
          System.out.println("done with the resource...");
        }
      }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    我们可以看到,当我们离开try块时,close()方法被调用。我们在进入try块时创建的实例在离开try块后就无法访问了。

    We can see the close() method was called as soon as we left the try block. The
    instance we created when entering the try block is not accessible beyond the
    point of leaving the block. The memory that instance uses will be garbage-collected
    eventually based on the GC strategy the JVM employs.

    Using Lambda Expressions to Clean Up Resources

    Preparing the Class for Resource Cleanup

    不像普通的工厂方法那样,创建一个实例并把它扔到栅栏对面。 我们的方法将把它交给用户,等待他们完成对它的工作。

    Unlike the regular factory methods that create an instance and throw it across the fence, our method will yield it to users and wait for them to finish their work with it.

    UseInstance是一个函数式接口,是Java编译器从lambda表达式或方法引用中自动合成的理想候选者。

    UseInstance is a functional interface, an ideal candidate for the Java compiler
    to automatically synthesize from lambda expressions or method references.

    我们可以使用java.function.Consumer接口,而不是定义我们自己的UseInstance;但是,由于该方法可能会抛出一个异常,我们需要在我们的接口中表明这一点。

    We could have used a java.function.Consumer interface instead of defining our own
    UseInstance; however, since the method may throw an exception, we needed to
    indicate that in our interface.

    Lambda表达式只能抛出作为被合成的抽象方法的签名的一部分而定义的检查过的异常。

    Lambda expressions can only throw checked
    exceptions defined as part of the signature of the abstract method being synthesized.

    我们创建了UseInstance接口,以便accept()方法可以接受一个通用类型的实例;在这个例子中,我们把它与具体的FileWriterEAM的实例联系起来。

    我们还设计了这个方法的实现可以抛出一个通用的异常X–同样,在这个例子中,我们把它与具体的IOException类联系起来。

    We created the UseInstance interface so that the accept() method can accept
    an instance of a generic type; in this example, we tied it down to an instance
    of a concrete FileWriterEAM.

    We also designed it so this method implementation could potentially throw a generic exception X—again, in this example tied to the concrete class IOException.

      public static void use(final String fileName, 
        final UseInstance<FileWriterEAM, IOException> block) throws IOException {
        
        final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
        try {
          block.accept(writerEAM);
        } finally {
          writerEAM.close();
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在use()方法中,我们收到两个参数,fileName和一个对接口UseInstance的引用。

    在这个方法中,我们实例化了FileWriterEAM,并在try和final块的安全避难所中,将该实例传递给我们即将创建的接口的accept()方法。

    当调用返回时,我们在最后块中调用实例的close()方法。

    类的使用者不用关心那些细节。

    In the use() method, we receive two parameters, fileName and a reference to an
    interface UseInstance.

    Within this method we instantiate FileWriterEAM, and within the safe haven of the try and finally block
    we pass the instance to an accept() method of our soon-to-be-created interface.

    When the call returns, we invoke the close() method on the instance in the finally block.

    Instead of using this construct, we could use ARM within the
    use() method. In any case, the users of our class don’t have to worry about
    these details.

    Using the Design for Instance Cleanup

    这么做的好处

    不用直接创建实例,专注于资源清理。可以使用short-and-sweet的lambda表达式调用use方法。

    First, our class’s users can’t create an instance directly. This prevents them
    from creating code that would postpone the resource cleanup beyond its
    expiration point (unless they go through extreme measures, such as using
    reflection, to defeat the mechanism). Since the compiler will prevent calls to
    the constructor or the close() method, the programmers will quickly figure out
    the benefit of the use() method, which yields an instance for their use. To
    invoke use(), they can use the short-and-sweet syntax that lambda expressions
    provide, as we saw in the previous code.

      public static void main(final String[] args) throws IOException {
      
        System.out.println("//" + "START:EAM_USE_OUTPUT");
        FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("first try lishizheng"));
        System.out.println("//" + "END:EAM_USE_OUTPUT");
    
        FileWriterEAM.use("eam2.txt", writerEAM -> {
            writerEAM.writeStuff("how");
            writerEAM.writeStuff("sweet");
            writerEAM.writeStuff("lishizheng");
          });
    
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Rather than shifting the
    burden on our class’s users, we put in a bit more effort that made their lives
    much easier and the behavior of our code a lot more consistent.

    英文

    tied to xx:联系起来 we tied it down to an instance of a concrete FileWriterEAM.

    wrap: 打包, wrap a call in the finally block.

    其他

    2022年11月29日15点46分学习这部分内容。

  • 相关阅读:
    智慧港口解决方案-最新全套文件
    RTP相关
    线上教育培训办公系统系统的设计
    MIKE水动力笔记12_数字化海图1之提取确值水深点
    Terra-Luna归零一年后:信任重建、加密未来路在何方?
    三、循环语句
    二、Docker基本操作
    【云原生之Docker实战】使用docker部署webssh工具
    Python和Tensorboard的下载和安装
    Table.Group系列_第4参数为全局的情况下,利用第5参数进行分组汇总
  • 原文地址:https://blog.csdn.net/shizheng_Li/article/details/128099646