CodeGym /Java Course /Java Core /Saving an Object array

Saving an Object array

Java Core
Level 10 , Lesson 1
Available

"Hello, Amigo! Today we'll learn about another interesting topic. Specifically, saving and loading (reconstructing) objects. Suppose we have a Cat class:"

Code
class Cat
{
 public String name;
 public int age;
 public int weight;
}

And let's say we want to add a convenient mechanism for saving to and loading from a file.

We could do it like this:

Code
class Cat {
    public String name;
    public int age;
    public int weight;

    public void save(PrintWriter writer) throws Exception {
        writer.println(name);
        writer.println(age);
        writer.println(weight);
        writer.flush();
    }

    public void load(BufferedReader reader) throws Exception {
        name = reader.readLine();
        age = Integer.parseInt(reader.readLine());
        weight = Integer.parseInt(reader.readLine());
    }
}

"Wow! That's so easy! We just write the values of each argument, one on each line. When we load the file, we read them in the same order. It's the perfect solution."

"Thanks, Amigo. Now you can write the save and load methods for this group of classes:"

Code
class Cat
{
 public String name;
 public int age;
 public int weight;
}
class Dog
{
 public String name;
 public int age;
}
class Human
{
 public Cat cat;
 public Dog dog;
}

You have an Human object, which can have one dog and one cat.

"I have a solution:"

Code
class Cat {
    public String name;
    public int age;
    public int weight;

    public void save(PrintWriter writer) throws Exception {
        writer.println(name);
        writer.println(age);
        writer.println(weight);
        writer.flush();
    }

    public void load(BufferedReader reader) throws Exception {
        name = reader.readLine();
        age = Integer.parseInt(reader.readLine());
        weight = Integer.parseInt(reader.readLine());
    }
}
Code
class Dog {
    public String name;
    public int age;

    public void save(PrintWriter writer) throws Exception {
        writer.println(name);
        writer.println(age);
        writer.flush();
    }

    public void load(BufferedReader reader) throws Exception {
        name = reader.readLine();
        age = Integer.parseInt(reader.readLine());
    }
}
Code
public class Human {
    public Cat cat;
    public Dog dog;

    public void save(PrintWriter writer) throws Exception {
        cat.save(writer);
        dog.save(writer);
    }

    public void load(BufferedReader reader) throws Exception {
        cat.load(reader);
        dog.load(reader);
    }
}

"That's a very good solution. But what happens if a human has a dog but no cat?"

Where are the null checks?

"I'll fix it now:"

Code
public class Human {
    public Cat cat;
    public Dog dog;

    public void save(PrintWriter writer) throws Exception {
        if (cat != null)
            cat.save(writer);
        if (dog != null)
            dog.save(writer);
    }

    public void load(BufferedReader reader) throws Exception {
        cat = new Cat();
        cat.load(reader);
        dog = new Dog();
        dog.load(reader);
    }
}

"It's still not quite right. You have two errors:"

1) A person might not have a cat or dog, but they will still be created when the load method is called

2) If we only save a dog, its data will be read by the cat when it is loaded.

"Well, what should I do?"

"We can't skip writing the variables, otherwise we'll have problems during reading. You need to make sure that variables that are null during the save operation are set to null during the load operation. Here's my version:"

Code
public class Human {
    public Cat cat;
    public Dog dog;

    public void save(PrintWriter writer) throws Exception {
        String isCatPresent = cat != null ? "yes" : "no";
        writer.println(isCatPresent);
        writer.flush();

        if (cat != null)
            cat.save(writer);

        String isDogPresent = dog != null ? "yes" : "no";
        writer.println(isDogPresent);
        writer.flush();

        if (dog != null)
            dog.save(writer);
    }

    public void load(BufferedReader reader) throws Exception {

        String isCatPresent = reader.readLine();
        if (isCatPresent.equals("yes")) {
            cat = new Cat();
            cat.load(reader);
        }

        String isDogPresent = reader.readLine();
        if (isDogPresent.equals("yes")) {
            dog = new Dog();
            dog.load(reader);
        }
    }
}

"Yes, I like this solution."

"Yeah, it's nice."

Comments (18)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Mike S Level 28, Saint Louis, United States
17 March 2023
So, I copied and pasted all of this code into IntelliJ to play around with the methods and make notes on them. I've made progress, but what's still murky is this and I feel like this is a key point to understand the exercises attached to this lecture--or at least the "Reading and writing static fields to a file" task. In line 25 and 31 of the Human class for the last code block, we create a new instance of Dog() and Cat() if the user has "yes" typed into some file or console. But that doesn't make sense. That's just some random dog or cat, not the one that the human owns. I feel like we should be parsing the human's data to find out if he or she owns a cat or dog...
Олег Байбула Level 32, Ukraine Expert
9 March 2023
I can't get it. The worst here is the form of dialogue. Feeling like I'm 8 years old.
Diego deFontenelle Level 27, Rennes, France
27 May 2021
Hi there, In order to understand the code below, I share this question : why should we create an object Cat even though the object already exists, according to the if condition? Many thanks in advance for yours answers :-). ============================================== CODE ZONE public void load(BufferedReader reader) throws Exception { String isCatPresent = reader.readLine(); if (isCatPresent.equals("yes")) { cat = new Cat(); cat.load(reader); } =========================================
Gellert Varga Level 23, Szekesfehervar, Hungary
16 November 2021
In my opinion, based on the lesson above: at some point in the past, we saved the 'Human' object in a file, so that it could be reconstructed at some later time. To be more precise, we didn't save the object itself, because the object can only exist in the memory of the machine, not in the file. Only the value (state) of its instance fields can be written to the file. For a primitive instance variable, we save the value itself. For a reference instance variable, however, there is no point in saving the reference: when/wherever you want to reconstruct the Human object (e.g. 2 weeks after or on another computer), the same cat/dog objects exist no longer; and their original references (memory addresses), if they exist now, store something else. So if the isCatPresent String variable was set to "yes", then you need to create a new Cat object and then load its primitive data fields. If, on the other hand, the isCatPresent String variable says that this past Human object's 'cat' field had a value of 'null', then we have to do nothing because the human.cat field of our newly created (reconstructed) 'human' object is created with a value of 'null' by default.
Mike S Level 28, Saint Louis, United States
17 March 2023
Exactly, Diego...
Mike S Level 28, Saint Louis, United States
17 March 2023
"For a primitive instance variable, we save the value itself." You're referring to this code in Dog or Cat class?

public void save(PrintWriter writer) throws Exception {
        writer.println(name);
        writer.println(age);
        writer.flush();
    }
"Only the value of its instance fields can be written to the file..." right... Ahh, okay. Thinking out loud here... "So if the isCatPresent String variable was set to "yes", then you need to create a new Cat object and then load its primitive data fields." Right... it does ultimately access that age, weight, name data for the dog or cat and it does that when you run the load() on the dog or cat within the human's load(). And that data for the dog or cat is presumably within that file or console input from the reader reference.
Halnik111 Level 29, Nitra, Slovakia
3 July 2020
if u guys r having trouble with this and upcoming set of tasks then dont worry. this is just some weird way to do serialize/deserialize. in next lessons u will learn how to do it the easy way.
Hiko Txs Level 20, Plano, United States
26 May 2020
what is the purpose save and load
Manish Sinha Level 26, london, United Kingdom
10 May 2020
i have difficulty understanding how this program works. hope i would get a complete example as i move on and would get chance to understand it better. Thanks codegym team for this lovely course.
Sanjay Chauhan Level 28, Delhi, India
28 March 2020
It's been 3 days and still trying to understand how to solve the tasks!! Let's see how many days it's going to eat more.
Pablo Saquilmer Level 32, Guatemala City, Guatemala
29 September 2020
jaja good one, but im the same
Jen P Level 26
10 August 2019
What is the purpose of

writer.flush(); 
at line 7, 15 of the very last example ? I checked online and flush() is to "ensure that anything written to the writer prior to the call to flush() is written to the underlying stream, rather than sit in some internal buffer." But I don't stand how our example related to this explanation. Thanks guys!
Ivaylo Trifonov Level 25, Madrid, Spain
1 November 2019
This function forces all the data stored internally in the writer buffer to be "released" to the target source (String, console output, File). Sometimes during his "work", the writer stores the data internally and then this data is not fully released when the writer terminates. I once was printing to the console a text from writer and the result was an empty string. Very strange. Then I called the flush() method and voila, finally had all my data printed.
Tangerin Level 27, Chongqing, China
21 July 2019
I was thinking there will be a more convenient mechanism going to introduce, but it seems... noop
Krisztian Level 24, Budapest, Hungary
15 July 2019
So we just expand the cat and dog object's all data with one other: is it exist or not. Okay.