简体   繁体   中英

How to handle invalid input

Can anyone suggest an example on how to handle invalid inputs, I have got the logic wrong for input from the keyboard. So, I need !myScanner.hasNextInt() or to put that loop in a method which I can reuse for ever.

package dayoftheyear;

import java.util.Scanner;

/**
 *
 * @author abdal
 */
public class DayOfTheYear {

    /**
     * Ask the user to enter a month, day, and year as integers
     * separated by spaces then display the number of the days since the
     * beginning of the year.
     * Don’t forget about leap year.
     * Sample: user inputs ‘3 1 2000’, output is ‘61’.
     * @param args Unused.
     */
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        String enter = "A-z";
        int a=31;
        int b=1;


        boolean dateCheck;
        int month;
        int day;
        int year;

        do {
            System.out.print("Enter a valid month day year separated by spaces");
            if (s.hasNextInt()) {
                month= s.nextInt();
                day=s.nextInt();
                year=s.nextInt();
                if (month >= b && month <= a || day>=b && day<=a || year>=b) {
                    int numberOfDay = countDays(month, day, year);
                    System.out.println(+ month + "/" + day + "/" + year + " is a day number " 
                                + numberOfDay + " of that year");
                    dateCheck = true;
                } else {
                    System.out.println("Enter a valid month day year separated by spaces");
                    dateCheck = false;
                }
            } else {
                System.out.println("Not a date");
                month = 0;
                day=0;
                year=0;
                s.next();
                dateCheck = false;
            }
        } while (!dateCheck);

    /**
     * Get the number of days since the start of the year.
     * Declare a 12 element array and initialize it with the number of
     * days in each month.
     * @param month Month to count from.
     * @param day Day of the month to count to.
     * @param year The year to count from.
     * @return Days since the start of the given year.
     */
    } public static int countDays(int month, int day, int year) {
        int monthLength[] = {
            31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        };
        int days = 0;
        if (isLeapYear(year) && month > 2) 
            days += 1;
        for (int i = 0; i < month - 1; i++) 
            days += monthLength[i];
        return days += day;
    }

    /**
     * Check if a year is a leap year.
     * @param year Year to check.
     * @return True if the year is a leap year.
     */

        public static boolean isLeapYear(int year) {
            if (year % 4 != 0) return false;
            else if (year % 100 != 0) return true;
            else return year % 400 == 0;
    }   
}

Replace

if (month >= b && month <= a || day>=b && day<=a || year>=b)

with

if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1)

A sample run after this change:

Enter a valid month day year separated by spaces: 13 1 2000
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 3 32 2000
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 3 1 2
3/1/2 is a day number 60 of that year

Update1: the following condition will hold good also for February

if ((month == 2 && day >= 1 && day <= 28 && year >= 1 && !isLeapYear(year))
        || (month == 2 && day >= 1 && day <= 29 && year >= 1 && isLeapYear(year))
        || (month != 2 && month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1)) 

A sample run:

Enter a valid month day year separated by spaces: 2 29 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 13 2 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 32 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 2 3
1/2/3 is a day number 2 of that year

Update2: the following code addresses all the issues raised in the comments

int monthLength[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((month == 2 && day >= 1 && day <= 28 && year >= 1 && !isLeapYear(year))
        || (month == 2 && day >= 1 && day <= 29 && year >= 1 && isLeapYear(year))
        || (month != 2 && month >= 1 && month <= 12 && day >= 1 && day <= monthLength[month-1] && year >= 1))

A sample run:

Enter a valid month day year separated by spaces: 2 29 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 13 2 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 32 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 6 31 2020
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 7 31 2020
7/31/2020 is a day number 213 of that year

Since date format is not subject to change in real world, it should be appropriate to use some hard coding. Dividing the problem into several methods is always recommended.

You could add following methods to your class:

private static boolean validDate(int month, int day, int year) {
    if (year < 1) {
        return false; // no B.C.
    }
    if (month > 1 && month < 13) {
        if (month == 2) { // handle February
            return validFeb(day, year);
        } else if (month % 2 == 1 && month < 8 
                || month % 2 == 0 && month >= 8) { // 31-day months
            return valid31(day);
        } else { // 30 day months
            return valid30(day);
        }
    }

    return false;
}

Validate 30-day months:

private static boolean valid30(int day) {
    if (day > 1 && day < 31) {
        return true;
    }
    return false;
}

Validate 31-day months

private static boolean valid31(int day) {
    if (day > 1 && day < 32) {
        return true;
    }
    return false;
}

Validate February

private static boolean validFeb(int day, int year) {
    if (isLeapYear(year)) {
        if (day > 1 && day < 30) {
            return true;
        }
    } else {
        if (day > 1 && day < 29) {
            return true;
        }
    }

    return false;
}

Then your do-while loop should look something like so:

do {
        System.out.print("Enter a valid month day year separated by spaces\n");
        if (s.hasNextInt()) month = s.nextInt();
            else s.next();
        if (s.hasNextInt()) day = s.nextInt(); 
            else s.next();
        if (s.hasNextInt()) year = s.nextInt(); 
            else s.next();

        int numberOfDaysSinceStart = 0;
        if (validDate(month, day, year)) {
            dateCheck = true;
            numberOfDaysSinceStart = countDays(month, day, year);
            System.out.println(month + "/" + day + "/" + year + " is a day number "
                + numberOfDaysSinceStart + " of that year");
        } else {
            dateCheck = false;
        }
    } while (!dateCheck);

You can add edge cases forever. There is a reason why time-related calculations are nightmare outsourced to libraries written by some poor souls that are paid to try to cover them all. Java has such built in, take a look at java.util.Calendar (Gregorian implementation). You set it to year/month/day, and it will puke out an exception if anything is wrong while trying to get the result.

Calendar c = Calendar.getInstance();
c.set(year, month, day);
try {
    c.getTime();
} catch (Exception e) {
    // wrong date format
}

I think the code below can help you, comment if you have any questions.

while(true) {
    try{
        System.out.print("Enter a valid month day year separated by spaces");
        month= s.nextInt();
        day=s.nextInt();
        year=s.nextInt();
        if (month >= 1 && month <= 12 || day>=1 && day<=31 || year>=1) {
            System.out.println(+ month + "/" + day + "/" + year + " is a day number "+ " of that year");
            break;
        } else {
            System.out.println("Enter a valid month day year separated by spaces");
        }
    } catch(InputMismatchException e) {
        System.out.println("Enter a valid month day year separated by spaces");
    }
    s.next();
}

thanks I updated my program and it is working;

        public static void main(String[] args) {
    Scanner s = new Scanner(System.in);

    int year = 0;
    int month = 0;
    int day = 0;
    boolean dateCheck;
    do {
    System.out.print("Enter a valid month day year separated by spaces\n");
    if (s.hasNextInt()) month = s.nextInt();
        else s.next();
    if (s.hasNextInt()) day = s.nextInt(); 
        else s.next();
    if (s.hasNextInt()) year = s.nextInt(); 
        else s.next();

    int numberOfDaysSinceStart = 0;
    if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1) {
        dateCheck = true;
        numberOfDaysSinceStart = countDays(month, day, year);
        System.out.println(month + "/" + day + "/" + year + " is a day number "
            + numberOfDaysSinceStart + " of that year");
    } else {
        dateCheck = false;
    }
} while (!dateCheck);

/**
 * Get the number of days since the start of the year.
 * Declare a 12 element array and initialize it with the number of
 * days in each month.
 * @param month Month to count from.
 * @param day Day of the month to count to.
 * @param year The year to count from.
 * @return Days since the start of the given year.
 */
} public static int countDays(int month, int day, int year) {
    int monthLength[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };
    int days = 0;
    if (isLeapYear(year) && month > 2) 
        days += 1;
    for (int i = 0; i < month - 1; i++) 
        days += monthLength[i];
    return days += day;
}

/**
 * Check if a year is a leap year.
 * @param year Year to check.
 * @return True if the year is a leap year.
 */
public static boolean isLeapYear(int year) {
    if (year % 4 != 0) return false;
    else if (year % 100 != 0) return true;
    else return year % 400 == 0;
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM