Always Close Resources

 class​ Logbook {
 
 static​ ​final​ Path LOG_FOLDER = Paths.get(​"/var/log"​);
 static​ ​final​ String FILE_FILTER = ​"*.log"​;
 
  List<Path> getLogs() ​throws​ IOException {
  List<Path> result = ​new​ ArrayList<>();
 
  DirectoryStream<Path> directoryStream =
  Files.newDirectoryStream(LOG_FOLDER, FILE_FILTER);
 for​ (Path logFile : directoryStream) {
  result.add(logFile);
  }
» directoryStream.close();
 
 return​ result;
  }
 }

Programs need system resources, such as disk space, database or network connections, CPU threads, and RAM. These resources are limited, and programs have to share them among each other. If a single program acquires resources without releasing them, it can bring down the whole environment. For a more in-depth explanation of this problem, take a look at this article.[35]

We the programmers need to prevent this! The plan sounds straightforward: free resources immediately when they’re no longer needed. But as always, the devil is in the details (or rather in the code).

Take a look at the method above. It uses a DirectoryStream, which is a system resource. It frees the resource by calling its close() method. Everything looks correct, doesn’t it?

Unfortunately not. When everything goes fine, the program opens the resource, uses it, and then closes it via the close() method. But what if the program opens the resource and an exception occurs while it’s using it, before it can free the resource by calling close()? An exception would prevent the execution of close(). Then, the resource wouldn’t be freed before the program terminates.

This is called a “resource leak.” It can harm the program itself if it tries to acquire the same resource again at a later time. And it’s definitely not the way to build a long-running application.

So how can we make sure that our code always closes its used resources?

 class​ Logbook {
 
 static​ ​final​ Path LOG_FOLDER = Paths.get(​"/var/log"​);
 static​ ​final​ String FILE_FILTER = ​"*.log"​;
 
  List<Path> getLogs() ​throws​ IOException {
  List<Path> result = ​new​ ArrayList<>();
 
»try​ (DirectoryStream<Path> directoryStream =
  Files.newDirectoryStream(LOG_FOLDER, FILE_FILTER)) {
 for​ (Path logFile : directoryStream) {
  result.add(logFile);
  }
  }
 
 return​ result;
  }
 }

Since Java 7, we can safely and elegantly close resources with the try-with-resources construct. This works for any class that implements the AutoCloseable interface, which practically all resource classes of the Java API do. We need to open only the resource within the round brackets following the try. Then, the resource is available in the scope of the try and Java takes care of calling close() when the block is finished, no matter what.

Actually, the try-with-resources is just syntactic sugar. The compiler expands it into something like this:

 DirectoryStream<Path> resource =
  Files.newDirectoryStream(LOG_FOLDER, FILE_FILTER);
 try​ {
 // usage of resource
 } ​finally​ {
 if​ (resource != ​null​) {
  resource.close();
  }
 }

That code opens the resource before the try and uses the finally block to ensure that the resource gets closed for normal and erroneous execution, but only when it’s not null to avoid a NullPointerException in the next line. This is clearly not as elegant and simple as try-with-resources.

You don’t really need the compiler here—you can implement resource closing on your own. In fact, before Java 7, that’s exactly what you had to do. But our advice is: let your code be elegant and let the compiler do the dirty work.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.223.10