3
\$\begingroup\$

this is my second program that I have made as a Java beginner (started out like two weeks ago). The program utilizes scanner and arraylist to create a to do list which the user can add to and print it at the end when they are done. I would like to know if there's anything I can improve or optimize in a more simple and elegant way :).

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Scanner;

public class ToDoList {
    static Scanner userInput = new Scanner(System.in);
    static ArrayList<String> userList = new ArrayList<>();

    public static void createList() {
        System.out.println("ToDoList Creator - Create to do lists using Java.");
        System.out.println("Type '!view' to exit and view your list.");
        System.out.println("Enter your tasks in the line below.");
        while (true) {
            System.out.print("-: ");
            String definedCommand = userInput.nextLine();
            SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy/MM/dd");
            Calendar currentDate = Calendar.getInstance();
            if (definedCommand.equals("!view")) {
                System.out.println("List's Date: " + simpleDate.format(currentDate.getTime()));
                for (int listSize = 0; listSize != userList.size(); listSize++) { 
                    System.out.println(listSize + 1 + ". " + userList.get(listSize));
                }
                break;
            } else {
                userList.add(definedCommand);
            }
        }
    }

    public static void main(String[] args) {
        createList();
    }
}
\$\endgroup\$
2
\$\begingroup\$

What you wrote is really good for someone that just started programming :) What you can do now is look at your code from a higher level

Initial comments

// this is not a todo list or "only" a todo list
public class ToDoList {
    // initialization - nothing much to see right now except naming 
    // userInput should be a scanner or sc
    // userList should be a todoList
    static Scanner userInput = new Scanner(System.in);
    static ArrayList<String> userList = new ArrayList<>();

    // This doesn't really create a list or "only" create a list
    public static void createList() {
        // welcome message / instructions
        System.out.println("ToDoList Creator - Create to do lists using Java.");
        System.out.println("Type '!view' to exit and view your list.");
        System.out.println("Enter your tasks in the line below.");

        // main loop
        while (true) {
            // input tag thingy - sorry don't know if this has a name
            System.out.print("-: ");

            // read a command
            String definedCommand = userInput.nextLine();

            // initialization of variables that will only be used when !view command
            // is present - hint hint
            SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy/MM/dd");
            Calendar currentDate = Calendar.getInstance();

            // if user typed view command
            if (definedCommand.equals("!view")) {
                // print list's date
                System.out.println("List's Date: " + simpleDate.format(currentDate.getTime()));

                // print list items
                for (int listSize = 0; listSize != userList.size(); listSize++) { 
                    System.out.println(listSize + 1 + ". " + userList.get(listSize));
                }

                // end loop
                break;
            } else {
                // add command to the todo list
                userList.add(definedCommand);
            }
        }
    }

    public static void main(String[] args) {
        createList();
    }
}

First step

The next objective is to get rid of the comments as much as possible.

public class TodoListApp {
    static Scanner sc = new Scanner(System.in);
    static ArrayList<String> todoList = new ArrayList<>();

    public static void main(String[] args) {
        start();
    }

    public static void start() {
        printInstructions();

        mainLoop();
    }

    private static void printInstructions() {
        System.out.println("ToDoList Creator - Create to do lists using Java.");
        System.out.println("Type '!view' to exit and view your list.");
        System.out.println("Enter your tasks in the line below.");
    }

    private static void mainLoop() {
        while (true) {
            printLineStart();

            String command = readCommand();
            
            if (isViewListCommand(command)) {
                printList();
                break;
            } else {
                addToTodoList(command)
            }
        }
    }

    private static void printLineStart() {
        System.out.print("-: ");
    }

    private static String readCommand() {
        return sc.nextLine();
    }

    private static boolean isViewListCommand(String command) {
        return command.equals("!view")
    }

    private static void printList() {
        SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy/MM/dd");
        Calendar currentDate = Calendar.getInstance();
        System.out.println("List's Date: " + simpleDate.format(currentDate.getTime()));

        for (int listSize = 0; listSize != todoList.size(); listSize++) { 
            System.out.println(listSize + 1 + ". " + todoList.get(listSize));
        }
    }

    private static void addToTodoList(String item) {
        userList.add(item);
    }
}

This is already a good first step. Comments are gone, the code is more split up and thus easier to read - it is clear what the code will do from method names without you having to figure it out from the code itself.

Splitting it up

You might notice that the class ToDoListApp is overworked - it reads the commands, manages the todo list and runs the program. The next step is to split this up into three classes, each doing it's job.

public class Main {
    public static void main(String[] args) {
        TodoList todoList = new TodoList();
        TodoListApp app = new TodoListApp(todoList);
        app.start();
    }
}

class TodoListApp {
    private boolean isRunning = true
    private Scanner sc = new Scanner(System.in);
    private TodoList todoList;

    public TodoListApp(TodoList todoList) {
        this.todoList = todoList;
    }

    public void start() {
        printInstructions();

        mainLoop();
    }

    private void printInstructions() {
        System.out.println("ToDoList Creator - Create to do lists using Java.");
        System.out.println("Type '!view' to exit and view your list.");
        System.out.println("Enter your tasks in the line below.");
    }

    private void mainLoop() {
        while(isRunning) {
            printLineStart();

            String command = readCommand();
            
            isRunning = executeCommand(command);
        }
    }

    private boolean executeCommand(String command) {
        if (isViewListCommand(command)) {
            todoList.printList();
            return false;
        } else {
            todoList.addToTodoList(command);
            return true;
        }
    }

    private void printLineStart() {
        System.out.print("-: ");
    }

    private String readCommand() {
        return sc.nextLine();
    }

    private boolean isViewListCommand(String command) {
        return command.equals("!view")
    }
}

class TodoList {
    private ArrayList<String> todoList = new ArrayList<>();

    private void addToTodoList(String item) {
        userList.add(item);
    }

    public void printTodoList() {
        System.out.println("List's Date: " + todaysDate());

        for (int index = 0; index < todoList.size(); index++) { 
            printItemAt(index);
        }

        // if you are feeling brave you can use the line below instead of the for loop:
        // IntStream.range(0, todoList.size()).forEach(this::printItemAtIndex)
        // .range() esentially returns you a list (not really, but close enough) of
        // integers from 0 to list size - [0, 1, 2, ..., 9] if list size = 10. Then 
        // printItemAtIndex gets called for each item in the array. If you don't 
        // understand this don't stress, come to it later.
    }

    private printItemAtIndex(int index) {
        System.out.println((index + 1) + ". " + todoList.get(index));
    }

    private todaysDate() {
        SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy/MM/dd");
        Calendar currentDate = Calendar.getInstance();

        return simpleDate.format(currentDate.getTime());
    }
}

Hopefully this is not too much for you to understand as it is a bit more lines of code and probably also a new concept of splitting the code up into smaller modules.

Edit:

Making it a CLI

So right now the code is split up nicely, the only friction I see is the following:

todoList.addToTodoList(command);

The thing added to the todo list is a command, which is odd - the CLI should have a format that is [command] [...options] [...arguments]. This allows you to have multiple commands - view, add, delete, exit. Right now you can only have commands that don't receive arguments. Command that is now "new todo item" would have to become "add new todo item". I hope it makes sense.

To do this you have to modify how you read the command and how the command is represented.

class TodoListApp {
...

    private void mainLoop() {
        while(isRunning) {
            printLineStart();

            // this now changed
            Command command = readCommand();
            
            isRunning = executeCommand(command);
        }
    }

    // You will have to implement this - eventually you will probably want to
    // move this into a separate class and pass it to the app through the constructor
    // the same way TodoList is passed in
    private Command readCommand() {
        ...

        return new Command(command, options, argument);
    }

    private boolean executeCommand(Command command) {
        if (isViewListCommand(command)) {
            todoList.printList();
            return true;
        } 
        // not else, but check if it is another command
        else if(isAddToListCommand(command)) {
            todoList.addToTodoList(command.argument());
            return true;
        }
        else if(isExitCommand()) { return false; }
        else {
            printListOfCommands();
        }
    }

    private boolean isViewListCommand(Command command) {
        return command.is("view"); // you can remove the ! now
    }

...
}

class Command {
    private String command;
    private Map<String, String> options;
    private String argument;

    // constructor to initialize the private parameters is left out

    public boolean is(String command) {
        return this.command.equals(command);
    }

    public boolean hasOption(String option) {
        ...
    }

    public String option(String option) {
        ...
    }

    public String argument() {
        return argument;
    }
}

Hopefully you understand this bit of code an will be able to implement it yourself. You can omit the Command options at the beginning and only have command and argument in the Command class just so you will parse the command easier. I have added the options in there so you have a structure to use moving forward.

Also, the executeCommand() if-elseif blocks might grow, so you might want to split them up in more objects like this:

...
        if (isViewListCommand(command)) {
            return new ViewList(command, todoList).execute();
        }
...

class ViewList {
    private Command command;
    private TodoList todoList;

    // constructor

    public boolean execute() {
        todoList.printList();
        return true;
    }
}

I have to note, that this is way over engineered for the program that you have now, but I am just telling you the tools that you can use if things start to blow up :)

\$\endgroup\$
2
  • \$\begingroup\$ I greatly appreciate this answer because that's eventually what I am aiming for at the end of learning the basics. Split up everything in separate classes and modules so it's easier to expand on rather than everything crammed in one class. Thank you for taking your time! (btw the tag thingy was made to look similar like a command line :p) \$\endgroup\$ Jul 6 at 20:17
  • \$\begingroup\$ Yeah I know it is made to look like a command line, I just have no idea what that is called and if it even has a name :D I left out one bit that that is not really correct and that is command parsing - it might be too advanced for you, but I will outline what you need to do and leave you to implement it \$\endgroup\$
    – Blaž Mrak
    Jul 7 at 4:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.