• 15 hours
  • Easy

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/28/24

Implement your design in Java

In this chapter, we are going to implement the design from the last chapter. First, we'll check how the concrete logic workflow is implemented inside the main function that starts the program. Then we'll see how the operations are implemented in a class.

Implement the logic workflow by sending messages

Phase 1: creating an object

First, you have to create a canvas for your work and add the main method:

public class MorningRoutine {
	public static void main(String[] args) {
		
	}
}

Remember that the public static void main(String[] args)  method is the starting point of the program. Everything that happens is defined between its opening curly brace { and its closing brace }. The main method is located in aMorningRoutine class. This means that when the code is compiled, the file used to start the program will be named MorningRoutine.class. 

In practice, that means you can open the terminal on your own computer, go to the folder where your code is located, and enter the following command:

javac MorningRoutine.java TodoList.java

This will compile the code and generate the file: MorningRoutine.classYou will then be able to run the program with the following command:

java MorningRoutine

Now you've got to create your object.  Use the class we've designed to make an object:

public class MorningRoutine {
	public static void main(String[] args) 
	{
		TodoList myTodoList = new TodoList("My morning routine");
	}
}

The TodoList myTodoList = new TodoList("My morning routine");  statement creates an object that is an instance of the TodoList class. This instance is assigned to a myTodoList variable. As you can see, you are sending a  "My morning routine" string as an argument. This string corresponds to the topic of the TodoList and is assigned to the topic attribute.

At this point, the myTodoList object has been created and is ready to receive messages. This means you can apply all the operations we discussed in the last chapter. 🤘

Phase 2: setting up the regular morning routine

You will first send messages adding regular morning routine tasks to your to-do list:

		public class MorningRoutine {
	public static void main(String[] args) 
	{
		TodoList myTodoList = new TodoList("My morning routine");
		myTodoList.addTask("Wake up");
		myTodoList.addTask("Shower");
		myTodoList.addTask("Have breakfast");
		myTodoList.addTask("Go to work");
	
}

As you can see, a message really means calling a method in the object with the appropriate arguments. You can now check that everything worked properly by calling the display() method.

public class MorningRoutine {
	public static void main(String[] args) 
	{
		TodoList myTodoList = new TodoList("My morning routine");
		myTodoList.addTask("Wake up");
		myTodoList.addTask("Shower");
		myTodoList.addTask("Have breakfast");
		myTodoList.addTask("Go to work");
		myTodoList.display();
	}
}

This generates the following output:

Here is our Todo List for My morning routine:

Task 0 is Wake up
Task 1 is Shower
Task 2 is Have breakfast
Task 3 is Go to work

Have you noticed how the Display() method takes no argument and still manages to get the work done? If you recall, a method has access to all the fields of the class it is defined in! This is what makes them so useful. ✨

Now that your regular morning routine has been stored, apply the changes for the day!

Phase 3: making changes to your daily routine

Start by removing breakfast and displaying the list again to make sure it worked.

When the list at the end of phase two was displayed, you saw that your  Have breakfast  task was located at position 2. You can use that information to send a remove message. Then display the list again:

public class MorningRoutine {
	public static void main(String[] args) 
	{
		TodoList myTodoList = new TodoList("My morning routine");
		myTodoList.addTask("Wake up");
		myTodoList.addTask("Shower");
		myTodoList.addTask("Have breakfast");
		myTodoList.addTask("Go to work");
		myTodoList.display();
		myTodoList.remove(2);
		myTodoList.display();
	}
}

The output unsurprisingly shows your list without the breakfast task. Success! 😁

Here is our Todo List for My morning routine:

Task 0 is Wake up
Task 1 is Shower
Task 2 is Go to work

Great! With so much time on your hands, you can replace your shower with a bath. 🛀🏿 Use the rename method, which takes two arguments:

  1. The index of the task you want to replace. As you can see in the previous output, the index of the Shower is 1.

  2. The new name for the task.

Here is the code:

public class MorningRoutine {
	public static void main(String[] args) 
	{
		TodoList myTodoList = new TodoList("My morning routine");
		myTodoList.addTask("Wake up");
		myTodoList.addTask("Shower");
		myTodoList.addTask("Have breakfast");
		myTodoList.addTask("Go to work");
		myTodoList.display();
		myTodoList.remove(2);
		myTodoList.display();
		myTodoList.rename(1, "Take bath");
		myTodoList.display();
	}
}

Let's check the final output:

Here is our Todo List for My morning routine:

Task 0 is Wake up
Task 1 is Take bath
Task 2 is Go to work 

Now that you have seen how the logic workflow of your program is implemented in Java, let's see how the class is actually implemented.

Define the class name and its fields

In order to implement this design, you must define in code:

  1. The name of the class, which should clearly communicate that you are creating a model for a to-do list. Use TodoList, which follows the official Java naming conventions.

  2. Attributes (fields) need to store the state of the class. As you saw in the first chapter, you need to store the topic and the list of tasks. 

  3. The methods you called in your workflow: add, remove, rename, display.

Start by defining the class and its fields. Implement each operation as methods of the class. Here is the code for the definition of the name and the fields of the TodoList class:

/** TodoList models the attributes
 * and the operations we can perform
 */
 public class TodoList {
	private String topic;
	private ArrayList<String> tasks;
//...
}

The code starts with a documentation comment, allowing you to generate a JavadocAfter the Javadoc, the following code  public class TodoList  defines:

  1. The accessibility level:  public  

  2. The class name: TodoList

These are followed by the opening curly brace{which marks the beginning of the class body. The body starts with the two fields of the class that correspond to the attributes defined in the last chapter:

  1.  String topic; is the field that stores the reason why the class is used.

  2. ArrayList<String> tasks; stores the actual class as a list of strings. 

You can now define the different operations that the objects, created from your custom to-do list datatype, will be able to perform.

Implement the object creation method

In the main method of the program, you used the following statement to create the object:

TodoList myTodoList = new TodoList("My morning routine");

We mentioned earlier that the "My morning routine" string is assigned to the topic field. In Java, this is done by defining a constructor in the class body. The role of the constructor is to initialize the fields when an object is created. Here is the code located between the opening and closing curly braces of the class:

/** TodoList instantiates a TodoList with the provided string as a topic for the list
* and allocates the memory for the list of tasks
* @param topic The topic for which the list is created for
*/
public TodoList(String topic) {
	this.topic=topic;
	this.tasks=new ArrayList<String>();
}

Let's break this up!

  •  public TodoList(String topic) is the signature of the constructor method.

    1. public means the constructor is accessible. 

    2. TodoList is the name of the constructor. As you can see, a constructor bears the same name as the class. This is a requirement!

    3. String topic is the parameter of the class which is needed to initialize the topic  field.

  • There are two statements inside the constructor method:

    1. this.topic=topic; assigns the value of the topic parameter into the topic field.

    2. this.tasks=new ArrayList<String>(); allocates the memory for the list. Failure to do so will cause the program to crash when trying to use the list.

 How does Java differentiate between topic as a field, and topic as the local variable defined as a parameter?

Even though the field and the local variable bear the same name, the field is prefixed with the  this keyword and the . operator. 

  1.    this is actually a reference to the object that will be created from the class. 

  2.  The . operator means that you access the element to its right belonging to the element to its left.

Therefore, the . between this and tasks means that you are "accessing the tasks element of the this reference."

Implement the addTask method

Let's implement your first method that will enable the program to add a task to your list. Here is the Java code for your addTask method: 

/** addTask appends the provided String at the end of the list
* @param taskName The description of the task to be added
*/
public void addTask(String taskName) {
	this.tasks.add(taskName);
}

The important thing to notice here is that the addTask method only needs one argument: the string to be added. Since the actual list is stored as a field named tasks, it is directly accessible from the method.

Let's look more closely at the one line of code inside the body of the method:  this.tasks.add(task);

  1. this is the reference to the object that will be created from the class. 

  2. tasks is the field that stores the tasks as a list.

  3. add is a method provided by the ArrayList class that adds the value of the task variable at the end of the list.

As you saw in the constructor case, this.tasks.add(task); really means "call the add method of the tasks field of the this reference."

You now understand why the myTodoList.addTask("Wake up"); statement added the first task of the day to your to-do list in the main method of your program. Let's now see how the second method, display(), is implemented.

Implement the display method

In order to visualize the content of a list, it is necessary to browse through all the elements of the list and display them, element by element. Here is the code:

/** display displays the topic of the list
 * and each task order and description 
 */
public void display() {
	if(this.tasks.size()==0){
		System.out.println("Our Todo List for " + topic + "is currently empty!");
	}else {
		System.out.println("Here is our Todo List for " + topic);
		for(int i=0;i<this.tasks.size();i++) {
			System.out.println("Task " + i + " is " + this.tasks.get(i));
		}
	}
}

Let's break this down:

  • Since the method is public, start with a Javadoc comment between  /** and */

  • The signature of the method is  public void display(). It does not define parameters as all its work will be performed in the fields.

  • Inside the method, start by testing if the list is empty with if(this.tasks.size()==0){

  • If it is, only display the topic of the to-do list:  System.out.println("Our Todo List for " + topic + "is currently empty!");

  • Else, you loop through the list to print its content item by item:

System.out.println("Here is our Todo List for " + topic);
for(int i=0;i<this.tasks.size();i++) {
    System.out.println("Task " + i + " is " + this.tasks.get(i));
}

That's it! Do not hesitate to take another look at the chapter on loops if you're not entirely clear.

Did you notice, when you studied your main method at the beginning of this chapter, that the list for your example started with a weird "Task 0" as the first task ? To refresh your memory, here is what we printed after adding the four tasks.

Here is our Todo List for My morning routine:
Task 0 is Wake up
Task 1 is Shower
Task 2 is Have breakfast
Task 3 is Go to work

Now you have two operations implemented for your class: add, and display. Let's now move on to the removeTask method.

Implement the removeTask method

If you were working with an array instead of a list, you would have to write complex code to shift the items located after the item to be removed in order to overwrite it.

Thankfully, the ArrayList collection lets you do this in one line!

Here is the code:

/** remove removes a task at the provided index 
 * @param i The index of the task to remove
 */
public void removeTask(int i) {
	try {
		this.tasks.remove(i);
	}
	catch (IndexOutOfBoundsException e) {
		System.out.println("Could not remove task, no task at this index!");
	}
}

 The basic structure is the same as the previous method: a Javadoc comment,  public  accessibility and a meaningful name. This time we do have a parameter: the index of the element to be removed.

Here are two remarkable features:

  1. We are using theremove method, as defined in the ArrayList documentation.

  2. The tasks.remove(i); statement is part of a  try .. catch  block. This is because the remove method will throw an exception if we provide an index outside the range of existing values. Catching that exception allows your program to continue by simply printing a message instead of crashing.

Let's complete our class implementation with our final method:  rename .

Implement the rename operation

The renaming operation is straightforward. Simply provide the position of the task to be renamed and its new value. As in the previous method, you will be relying on a method provided by the ArrayList class.

Here's the code:

/** rename renames the task at the provided index
 * 
 * @param i The index of the task to rename
 * @param newtask The new description for the task
 */
public void rename(int i, String newTask) {
	try {
		this.tasks.set(i,newTask);
	}
	catch (IndexOutOfBoundsException e) {
		System.out.println("Could not rename task, no task at this index!");
	}
}

Compared to the removeTask method, you'll notice two main differences:

  1. You need two parameters: the index of the task to be renamed, and the new name.

  2. You are now using the set method of the ArrayList class. 

For both the removeTask and the rename methods, things get more complicated if you don't know the index. In that case, you need to search for the value by looping through the list. Once you have the index that contains the value, you can call the methods defined above.

Summary

In this chapter, you have created a well-documented class that can be used in any project where you may need a to-do list.

Throughout this chapter, you have seen that object-oriented programming in general and Java  programming in particular really consists of implementing a two-level thought process:

  1. Implement the capabilities you need as blueprints named classes that implement the needed operations as methods. Those methods operate on fields that are variables that define the state of the class. 

  2. Implement the logic of your program by creating instances of classes called objects. Things happen by sending messages to objects.

In the next chapter, we will enhance what your to-do list can do by allowing you to mark a task as completed, learning some cool new things along the way.

Example of certificate of achievement
Example of certificate of achievement