We previously looked at resource cleanup in C++.

C++ has smart objects that release their resources when they go out of scope.

Java also has objects that release their resources when they are no longer used.

However, Java doesn't clean up its objects immediately after they stop being used.

This is because memory management can be an expensive operation, so batching it up with other memory cleanups can be useful.

However, since you can't assume that the smart objects have cleaned themselves up after they are no longer referenced, you need to explicitly tell them to clean up.

To make this easier, Java has a finally block to go with its try block, which is always executed, so you don't need separate cleanup code in your success path and error path.

import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("Must be given 1 argument\n");
        }
        FileReader input;
        try {
            input = new FileReader(args[0]);
        } catch (FileNotFoundException e) {
            System.exit(1);
            return; /* unreachable, but javac is dumb */
        }
        try {
            char[] buf = new char[1024];
            int ret;
            while ((ret = input.read(buf, 0, buf.length)) != -1){
                String s = new String(buf, 0, ret);
                System.out.print(s);
            }
        } catch (IOException e) {
            System.err.println("Failure while writing file contents\n");
        } finally {
            try {
                input.close();
            } catch (IOException e) {
            }
        }
    }
}

Python also has a finally block, with much less verbose syntax.

#!/usr/bin/python
import sys
if len(sys.argv) != 2:
    sys.stderr.write("Must be given 1 argument\n")
try:
    input = open(sys.argv[1], 'r')
    while True:
        d = input.read(1024)
        if not d:
            break
        sys.stdout.write(d)
finally:
    input.close()

A downside to the try...finally idiom, is that it litters your code with the cleanup code for resources you acquire. The RAII idiom from C++ handles this by putting the cleanup code in the destructors.

Unfortunately, while python may have deterministic resource cleanup from reference counting like C++ (Iron Python and Jython may not), you can't reliably write your own destructors in python.

To make this nicer, python has with blocks, which allow the code for cleanup to be kept with the code for allocation.

To use a with block, you pass it an object that obeys the context manager protocol. There are dedicated context manager objects, and some other objects, such as open files, can be used as context managers.

With context managers, the code now looks like:

#!/usr/bin/python
import sys
if len(sys.argv) != 2:
    sys.stderr.write("Must be given 1 argument\n")
with open(sys.argv[1], 'r') as input:
    while True:
        d = input.read(1024)
        if not d:
            break
        sys.stdout.write(d)

To create your own context manager, you can write it like this:

#!/usr/bin/python
import contextlib
import sys
@contextlib.contextmanager
def open_input(path):
    input = open(path, 'r')
    try:
        yield input
    finally:
        input.close()
if len(sys.argv) != 2:
    sys.stderr.write("Must be given 1 argument\n")
with open_input(sys.argv[1]) as input:
    while True:
        d = input.read(1024)
        if not d:
            break
        sys.stdout.write(d)

Java 7 supports try-with-resources which allows automatic closing of resources (e.g. streams) that implement AutoCloseable. The resources are local to the try-block.

There's a tutorial by Oracle at https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html for anyone interested.

Comment by www.cloudid.de/?user=a47602f3eec8afceacef3dd015129173fa461fb1 Wed Nov 12 14:48:01 2014