3
\$\begingroup\$

I created a Student Management System based on these directions:

  • Ask the user how many new students will be added to the database
  • The user should be prompted to enter the name and the year for each student
  • The student should have a 5-digit unique ID with the first number being their grade level
  • A student can enroll in the following courses: History 101, Mathematics 101, English 101, Chemistry 101, & Computer Science 101
  • Each course costs $600
  • The student should be able to view their balance and pay their tuition
  • To see the status of the student, we should see their name, ID, courses enrolled, and balance

I wanted to get other people's opinions on:

  1. How are my comments for this program this is my first using JavaDoc style comments?
  2. What ways could I refactor the addCourses and payForCourses methods to make smaller and cleaner?
  3. Should I be using double or float instead of BigDecimal for the tuition?
  4. How can I reduce the code in my main method?

import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.math.BigDecimal;

public class Student {
    private String firstName;
    private String lastName;
    private String id;
    private List<String> courses;
    private BigDecimal tuition;
    private Scanner keyboard = new Scanner(System.in);

private Student(String fName, String lastName) {
    this.firstName = fName;
    this.lastName = lastName;
}

private Student() {

}

//Getters and Setters
private BigDecimal getTuition() { return tuition; }

private void setTuition(BigDecimal money) {
    this.tuition = money;
}

private String getName() { return firstName + " " +  lastName; }


private void setFirstName(String firstName) { this.firstName = firstName; }

private void setLastName(String lastName) { this.lastName = lastName; }

private String getId() { return id; }

private void setId(String id) { this.id = id; }

private List<String> getCourses() { return courses; }

private void setCourses(List<String> courses) { this.courses = courses; }

/**
 * Creates a id using a number from 1 - 4 given by the user and a random string of length 4.
 */
private void makeID()
{
    String grade;
    boolean checked = false;

    while (!checked)
    {
        System.out.println("Enter your school year 1. Freshman, 2. Sophomore, 3.Junior and 4. Senior ");
        grade = keyboard.nextLine();
        if (grade.length() == 1 && Integer.parseInt(grade) > 0 && Integer.parseInt(grade) < 5)
        {
            setId(grade.concat(randomString()));
            checked = true;
        } else {
            System.out.println("The input you enter is incorrect please try again");
        }
    }

}

/**
 * Returns a randomly generated 4 character string that will combined with a number entered by the user to make the student id.
 *
 * @return The four character random string
 */
private String randomString()
{
    String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    Random random = new Random();
    int great = AB.length();
    int temp;
    String codeword = "";
    for (int i = 0; i < 4; i++)
    {
        temp = (int) (random.nextFloat() * great);
        codeword = codeword.concat(Character.toString(AB.charAt(temp)));
    }
    return codeword;
}

/**
 * A payment system that allows the user to make multiple payments on their tuition
 */
private void payForCourses()
{
    String answer;
    BigDecimal payment;
    BigDecimal moneyLeftOver;

    while (getTuition().compareTo(BigDecimal.ZERO) > 0)
    {
        System.out.println("Your current balance is $" + getTuition());
        System.out.println("Do you want pay off you balance right now");

        answer = keyboard.nextLine();

        if (answer.toLowerCase().equals("yes"))
        {
            System.out.println("How much would you like to pay right now");

            if (keyboard.hasNextBigDecimal())
            {
                payment = keyboard.nextBigDecimal();
                payment = payment.setScale(2, RoundingMode.HALF_UP);
                keyboard.nextLine();
                if ((payment.compareTo(BigDecimal.ZERO) > 0) && payment.compareTo(getTuition()) <= 0)
                {
                    moneyLeftOver = getTuition().subtract(payment);
                    setTuition(moneyLeftOver);
                } else if (payment.compareTo(getTuition()) > 0) {
                    System.out.println("The value you have given is greater than your tuition");
                } else if (payment.compareTo(BigDecimal.ZERO) < 0) {
                    System.out.println("You gave an negative number as a payment value. Please enter a positive value next time");
                }

            } else {
                keyboard.nextLine();
                System.out.println("You entered the wrong input so please input a number next time.");
            }

        } else if (answer.toLowerCase().equals("no")) {
            break;
        } else {
            System.out.println("You gave the wrong input either enter yes or no");
        }
    }
}

/**
 * Gives the student the class they entered the corresponding number for a class
 *
 * @param classes - A list that contains the classes a student has at the moment.
 * @param courseNumber - A number that represent a particular class.
 */
private void chooseCourses(List<String> classes, int courseNumber)
{
    switch (courseNumber)
    {
        case 1:
            if (checkDups(classes, "History 101"))
                classes.add("History 101");
            break;
        case 2:
            if (checkDups(classes, "Mathematics 101"))
                classes.add("Mathematics 101");
            break;
        case 3:
            if (checkDups(classes, "English 101"))
                classes.add("English 101");
            break;
        case 4:
            if (checkDups(classes, "Chemistry 101"))
                classes.add("Chemistry 101");
            break;
        case 5:
            if (checkDups(classes, "Computer Science 101"))
                classes.add("Computer Science 101");
            break;
        default:
            System.out.println("You gave the wrong input");
            break;
    }
}

/**
 * Allows the user to add classes keeping track of classes they already added and setting the new tuition the user has.
 */
private void addCourses()
{
    List<String> classes = new LinkedList<>();
    setCourses(classes);

    String answer;
    int nextCourse;
    BigDecimal size;
    BigDecimal cost;

    System.out.println("Do you want to add any courses? yes or no");
    answer = keyboard.nextLine();
    while (!answer.toLowerCase().equals("no"))
    {
        if (answer.toLowerCase().equals("yes"))
        {
            System.out.println("Which classes would you like to add now? Please choose from the following selection. " +
                    "Choose the number for the courses");
            System.out.println("1. History 101");
            System.out.println("2. Mathematics 101");
            System.out.println("3. English 101");
            System.out.println("4. Chemistry 101");
            System.out.println("5. Computer Science 101");

            if (keyboard.hasNextInt())
            {
                nextCourse = keyboard.nextInt();
                keyboard.nextLine();
                chooseCourses(classes, nextCourse);

            } else {
                System.out.println("You put in the wrong input: Enter a number 1 - 5 for each class");
                keyboard.nextLine();
            }

        } else {
            System.out.println("You put in the wrong input: Enter either yes or no next time");
        }

        System.out.println("Do you want to add any more courses?");
        answer = keyboard.nextLine();
    }
    size = new BigDecimal(classes.size());
    cost = new BigDecimal(600);

    cost = cost.multiply(size);
    setTuition(cost);
}

/**
 * Make sure every class in a given list in unique.
 *
 * @param list - The list containing the student's current classes
 * @param word - The string that being checked to see if it is unique in the list
 * @return Whether or not the string is already in the list
 */
private boolean checkDups(List<String> list, String word)
{
    for (String temp : list)
    {
        if (word.equals(temp))
        {
            System.out.println("You are already enrolled in that course");
            return false;
        }
    }
    return true;
}

/**
 * Prints out each student's name, id, courses, and the current balance for tuition
 *
 * @param studentList - All the students enrolled and in the list
 */
private void displayInfo(Student[] studentList)
{
    for (Student student : studentList)
    {
        System.out.println("Student Name: " + getName());
        System.out.println("Student ID: " + student.getId());

        if (student.getCourses().size() > 0) {
            System.out.println("Student's Current Courses:" + student.getCourses());
        } else {
            System.out.println("Student's Current Courses: The student isn't enrolled in any courses");
        }
        System.out.println("Student's Current Balance: $" + student.getTuition());
        System.out.println("------------------------------------------------------");
    }

}

public static void main(String[] args) {
    try {
        int size;
        Scanner keyboard = new Scanner(System.in);
        System.out.println("Please enter the number of students you wish to add to the system");
        size = keyboard.nextInt();
        keyboard.nextLine();

        Student[] students = new Student[size];
        Student student;
        String firstName = "";
        String lastName = "";

        for (int i = 0; i < size; i++)
        {
            student = new Student(firstName, lastName);
            students[i] = student;

            System.out.println("Please enter your first name for Student ");
            firstName = keyboard.nextLine();
            student.setFirstName(firstName);

            System.out.println("Please enter your last name");
            lastName = keyboard.nextLine();
            student.setLastName(lastName);

            student.makeID();
            student.addCourses();
            student.payForCourses();

            if (i == size - 1)
                student.displayInfo(students);
        }
    } catch (NegativeArraySizeException e) {
        System.out.println("You can't use a negative number for size");

    }
}
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You are correct in using BigDecimal for storing monetary values. You should look into using java.util.concurrent.ThreadLocalRandom for randomString(), instead of java.util.Random. I would also not use a magic number for the length. \$\endgroup\$ – esote Jul 29 '18 at 23:56
  • 1
    \$\begingroup\$ You could split the UI code away from the student class. Have a StudentManager or AdmissionsUI class which manages the user interaction. \$\endgroup\$ – Teddy Jul 30 '18 at 2:45
1
\$\begingroup\$

A single student class managing the other students seems odd somehow. In fact, this has lead to a couple of bugs in your code. For example, in the displayInfo method you are iterating and printing all the students' information one by one, but you are always printing this.getName() instead of student.getName().

Also, the interface being command line should have very less to do with the student. So, lets split up the student creation, details collection etc. to a different class.

Here is the modified Student class, which manages only the state for a single student:

public class Student {
    public enum Course{
        HISTORY_101("History 101"), MATH_101("Mathematics 101"), 
        ENGLISH_101("English 101"), CHEMISTRY_101("Chemistry 101"), 
        CS_101("Computer Science 101");

        private String title;
        Course(String title) {
            this.title = title;
        }
        public String getTitle() {
            return title;
        }
    }

    private String firstName;
    private String lastName;
    private String id;
    private final List<Course> courses = new ArrayList<>();
    private BigDecimal tuition = BigDecimal.ZERO; //Default zero

    /** 
     * Package private, so that only admissions class can create this.
     */
    Student(String id, String fName, String lastName) {
        this.id = id;
        this.firstName = fName;
        this.lastName = lastName;
    }

    // Getters and Setters
    public BigDecimal getTuition() {
        return tuition;
    }

    private void setTuition(BigDecimal money) {
        this.tuition = money;
    }

    public String getName() {
        return firstName + " " + lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<Course> getCourses() {
        return courses;
    }

    public void addCourses(List<Course> courses) {
        if(courses!=null) {
            this.courses.addAll(courses);
            this.setTuition(this.getTuition().add( 
                    new BigDecimal("600").multiply( new BigDecimal( courses.size() ) ) 
                ) );
        }
    }

    public void makePayment(BigDecimal thisPayment) {
        //Backup validation built into student class
        if(thisPayment==null || thisPayment.compareTo(BigDecimal.ZERO)<=0 ) {
            throw new IllegalArgumentException("Invalid payment amount.");
        }else if(thisPayment.compareTo(this.getTuition())>0) {
            throw new IllegalArgumentException("Payment exceeds tuition amount.");
        }
        this.setTuition( this.getTuition().subtract(thisPayment) );
    }
}

Here is the AdmissionsUI class, which is deeply tied to the user interaction.

public class AdmissionsUI {
    private Scanner keyboard = null;
    private Student[] students = null;


    public static void main(String[] args) {
        AdmissionsUI adminInterface = new AdmissionsUI(); 
        try( Scanner keyboardAutoClose = new Scanner(System.in) ) {
            adminInterface.keyboard = keyboardAutoClose;

            System.out.println("Please enter the number of students you wish to add to the system");
            int size = adminInterface.keyboard.nextInt();
            adminInterface.keyboard.nextLine();
            adminInterface.students = new Student[size];

            for (int i = 0; i < size; i++) {

                System.out.println("Please enter your first name for Student ");
                String firstName = adminInterface.keyboard.nextLine();
                System.out.println("Please enter your last name");
                String lastName = adminInterface.keyboard.nextLine();
                String id = adminInterface.makeID();

                Student student = new Student(id, firstName, lastName);
                adminInterface.students[i] = student;

                adminInterface.addCourses(student);
                adminInterface.payForCourses(student);

                if (i == size - 1)
                    adminInterface.displayStudentsInfo();
            }
        } catch (NegativeArraySizeException e) {
            System.out.println("You can't use a negative number for size");

        }
    }

    /**
     * Prints out each student's name, id, courses, and the current balance for
     * tuition
     *
     * @param studentList
     *            - All the students enrolled and in the list
     */
    private void displayStudentsInfo() {
        for (Student student : students) {
            System.out.println("Student Name: " + student.getName());
            System.out.println("Student ID: " + student.getId());

            if (student.getCourses().size() > 0) {
                System.out.print("Student's Current Courses:" );
                for(Course sc:student.getCourses()) {
                    System.out.print(sc.getTitle() + " ");
                }
                System.out.println();
            } else {
                System.out.println("Student's Current Courses: The student isn't enrolled in any courses");
            }
            System.out.println("Student's Current Balance: $" + student.getTuition());
            System.out.println("------------------------------------------------------");
        }

    }

    /**
     * Allows the user to add classes keeping track of classes they already added
     * and setting the new tuition the user has.
     */
    private void addCourses(Student student) {
        List<Course> classes = new LinkedList<>();


        String answer;
        int nextCourse;

        System.out.println("Do you want to add any courses? yes or no");
        answer = keyboard.nextLine();
        while (!answer.toLowerCase().equals("no")) {
            if (answer.toLowerCase().equals("yes")) {
                System.out
                        .println("Which classes would you like to add now? Please choose from the following selection. "
                                + "Choose the number for the courses");

                int i=1;
                for(Course c:Course.values()) {
                    System.out.println(i++ + " " + c.getTitle());
                }

                if (keyboard.hasNextInt()) {
                    nextCourse = keyboard.nextInt();
                    keyboard.nextLine();
                    classes.add( Course.values()[nextCourse-1] );

                } else {
                    System.out.println("You put in the wrong input: Enter a number 1 - 5 for each class");
                    keyboard.nextLine();
                }

            } else {
                System.out.println("You put in the wrong input: Enter either yes or no next time");
            }

            System.out.println("Do you want to add any more courses?");
            answer = keyboard.nextLine();
        }
        student.addCourses(classes);
    }

    /**
     * A payment system that allows the user to make multiple payments on their
     * tuition
     */
    private void payForCourses(Student student) {
        while (student.getTuition().compareTo(BigDecimal.ZERO) > 0) {
            System.out.println("Your current balance is $" + student.getTuition());
            System.out.println("Do you want pay off you balance right now");

            String answer = keyboard.nextLine();

            if (answer.toLowerCase().equals("yes")) {
                System.out.println("How much would you like to pay right now");

                if (keyboard.hasNextBigDecimal()) {
                    BigDecimal payment = keyboard.nextBigDecimal();
                    payment = payment.setScale(2, RoundingMode.HALF_UP);
                    keyboard.nextLine();
                    if ((payment.compareTo(BigDecimal.ZERO) > 0) && payment.compareTo( student.getTuition()) <= 0) {
                        student.makePayment(payment);
                    } else if (payment.compareTo(student.getTuition()) > 0) {
                        System.out.println("The value you have given is greater than your tuition");
                    } else if (payment.compareTo(BigDecimal.ZERO) < 0) {
                        System.out.println(
                                "You gave an negative number as a payment value. Please enter a positive value next time");
                    }

                } else {
                    keyboard.nextLine();
                    System.out.println("You entered the wrong input so please input a number next time.");
                }

            } else if (answer.toLowerCase().equals("no")) {
                break;
            } else {
                System.out.println("You gave the wrong input either enter yes or no");
            }
        }
    }

    /**
     * Creates a id using a number from 1 - 4 given by the user and a random string
     * of length 4.
     */
    private String makeID() {
        String grade;
        while (true) { //Returns from method when done
            System.out.println("Enter your school year 1. Freshman, 2. Sophomore, 3.Junior and 4. Senior ");
            grade = keyboard.nextLine();
            if (grade.length() == 1 && Integer.parseInt(grade) > 0 && Integer.parseInt(grade) < 5) {
                return grade.concat(randomString());
            } else {
                System.out.println("The input you enter is incorrect please try again");
            }
        }
    }

    /**
     * Returns a randomly generated 4 character string that will combined with a
     * number entered by the user to make the student id.
     *
     * @return The four character random string
     */
    private String randomString() {
        String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        Random random = new Random();
        int great = AB.length();
        int temp;
        String codeword = "";
        for (int i = 0; i < 4; i++) {
            temp = (int) (random.nextFloat() * great);
            codeword = codeword.concat(Character.toString(AB.charAt(temp)));
        }
        return codeword;
    }
}

I haven't updated the JavaDocs though to reflect the modifications.

\$\endgroup\$
  • \$\begingroup\$ I have a couple of questions: What's the purpose of having addCourses method (in the Student class) and makePayment method if they are never called? and Do you have any tips for refactoring code? Thanks for looking at my code btw. \$\endgroup\$ – Jameell Jul 30 '18 at 4:50
  • \$\begingroup\$ Student. addCourses is in fact used in AdmissionsUI.addCourses. And also Student.makePayment is used in AdmissionsUI.payForCourses \$\endgroup\$ – Teddy Jul 30 '18 at 5:08
  • 1
    \$\begingroup\$ Other than the classes-split, the code looks good. You have kept each sub process of user interaction in a method.. so its cohesive. Small things can be changed, like moving the repeated sysout's to a static display method and so on. But, it already looks good. \$\endgroup\$ – Teddy Jul 30 '18 at 5:13

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.