List passed into method and deserialised becomes empty once method returns

I have a method:

static <E extends NotesAttached> void deserialise(List<E> list, String type) {
    String fileName = "C:/temp/SalesModel." + type + ".list.ser";
    try {
        FileInputStream serFile = new FileInputStream(fileName);
        ObjectInputStream in = new ObjectInputStream(serFile);
        list = (List<E>) in.readObject();
        in.close();
        serFile.close();
        System.out.println(type + "s deserialised successfully, " + list.size() + " retrieved");
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

I call it like this:

    List<Deal> deals = new ArrayList<Deal>();
    deserialise(deals, "Deal");
    System.out.println("Number of deals deserialised: " + deals.size());

The list is populated when its in the method, but when it returns, its empty. I don't understand why, would appreciate it if someone could explain.

The output is as follows:

Deals deserialised successfully, 2522 retrieved Number of deals deserialised: 0

Jon Skeet
people
quotationmark

The list you've deserialized doesn't "become empty" - but the deals variable doesn't refer to the list you've just deserialized... it refers to the same empty list that it did before you called the method. Changing the value of the list parameter within the method does nothing to the argument you've passed, because Java uses pass by value.

Rather than having a void method, you'd be better off returning the list:

static <E extends NotesAttached> List<E> deserialise(String type)
        throws IOException, ClassNotFoundException {
    String fileName = "C:/temp/SalesModel." + type + ".list.ser";
    FileInputStream serFile = new FileInputStream(fileName);
    ObjectInputStream in = new ObjectInputStream(serFile);
    try {
        List<E> list = (List<E>) in.readObject();
        System.out.println(type + "s deserialised successfully, " + list.size() + " retrieved");
        return list;
    } finally {
        // See notes
        in.close();
        serFile.close();
    }
}

And call it with:

List<Deal> deals = deserialise(deals, "Deal");
System.out.println("Number of deals deserialised: " + deals.size());

You'll need to deal with the ClassNotFoundException and the IOException, but they're better off being dealt with outside the method anyway - you almost certainly don't want to just catch them, dump a stack trace and continue as if nothing had gone wrong.

That's not quite right, as you really want to close the streams regardless of other errors. If you can use Java 7, you can use a try-with-resources statement instead:

static <E extends NotesAttached> List<E> deserialise(String type)
        throws IOException, ClassNotFoundException {
    String fileName = "C:/temp/SalesModel." + type + ".list.ser";
    try (FileInputStream serFile = new FileInputStream(fileName),
         ObjectInputStream in = new ObjectInputStream(serFile)) {
        List<E> list = (List<E>) in.readObject();
        System.out.println(type + "s deserialised successfully, " + list.size() + " retrieved");
        return list;
    }
}

If you're stuck with Java 6, I'd probably use nested try/finally blocks - or only close the FileInputStream, given that the ObjectInputStream doesn't hold onto any unmanaged resources anyway.

people

See more on this question at Stackoverflow