Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

  • Valid User Input

    This class simplifies the common task of asking the user for valid input. It was designed to be as simple to use as possible.

    Example usage:
    //Ask for the users name
    String name = Console.readString("Enter your name:");
     
    //Ask for the users age (between 6 and 110)
    int age = Console.readInteger("Enter you age:", "You cannot be that old!", 6, 110);
     
    //Ask for a float
    float pay = Console.readFloat("How much do you earn per hour:");
     
    //Ask for a double
    double pi = Console.readDouble("Enter as many digits of PI as you can remember:");
     
    //Ask a yes/no question
    boolean isProgrammer = Console.readYesNo("Are you a programmer [YES or NO]:");
     
    //Ask for an integer with the default prompt
    int i0 = Console.readInteger();
     
    //Ask for an integer with a custom prompt
    int i1 = Console.readInteger("Enter a number: ");
     
    //Ask for an integer with a custom prompt and custom error message
    int i2 = Console.readInteger("Enter a number: ", "Try again.");
     
    //Ask for an integer in the range 1..10 with a custom prompt and custom error message 
    int i3 = Console.readInteger("Enter a number between 1 and 10", "Not in range.", 1, 10);
     
    //Ask if the user would like to quit (put this in an infinite loop)
    if (Console.readYesNo("Really Quit [y/n]")) { System.exit(0); }


    Here is the class.

    Console.java
     
    import java.io.IOException;
     
    /**
     * Console.java
     * 
     * This class is a convinence wrapper for the common task of
     * asking for user input. Features include:
     *      - recusive input validation for all primitive types
     *      - overloaded methods for lazy usage or informative prompting
     *	 - consistant, meaningful prompting behaviour
     *
     *      
     * 
     *  Some usages: 
     *      - int i1 = Console.readInteger("Enter a number: ");
     *      - int i2 = Console.readInteger("Enter a number: ", "Try again.");
     *      - int i3 = Console.readInteger("Enter a number between 1 and 10", "Not in range.", 1, 10);
     *      - float f = Console.readFloat("Enter a decimal number: ");
     *      - if (Console.readYesNo("Really Quit [y/n]")) { System.exit(0); }
     *      
     * 
     * @author Christopher Lowe 
     * @version 5/4/2011
     * 
     */
    public class Console
    {
     
    	private static final String CONSOLE = "> ";
    	private static final String DEFAULT_PROMPT = "Enter input: ";
    	private static final String DEFAULT_RETRY = "Invalid Input. Try again.";
     
     
    	/**
    	 * Prompts the user for a YES/NO input. It will default to false on incorrect input.
    	 *
    	 * @param prompt The message asking for user input
    	 * @return true if the user inputs "Y", "y", "yes", "YES" or "YeS"
    	 */
    	public static final boolean readYesNo(String prompt) {
    		String input = readLine(prompt).toLowerCase().trim();
    		if (input.equals("yes") || input.equals("y")) {
    			return true;
    		}
    		//Behavioural: only a discrete 'yes' will return true.
    		//It does not recurse on invalid input because incorrect input
    		//is logically identical to the non-destructive 'no'
    		return false;
    	}
     
    	/**
    	 * Prompts the user for YES/NO input. It will default to false on incorrect input.
    	 *
    	 * @return true if the user inputs "Y", "y", "yes", "YES" or "YeS"
    	 */
    	public static final boolean readYesNo() {
    		return readYesNo(DEFAULT_PROMPT);
    	}
     
    	/**
    	 * Prompts the user for YES/NO input. It will default to false on incorrect input.
    	 *
    	 * @param prompt The message asking for user input
    	 * @return true if the user inputs "Y", "y", "yes", "YES" or "YeS"
    	 */
    	public static final boolean readBoolean(String prompt) {
    		return readYesNo(prompt);
    	}
     
    	/**
    	 * Prompts the user for YES/NO input. It will default to false on incorrect input.
    	 *
    	 * @return true if the user inputs "Y", "y", "yes", "YES" or "YeS"
    	 */	 
    	public static final boolean readBoolean() {
    		return readYesNo(DEFAULT_PROMPT);
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input in a given range.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @param error The error message to inform the user that the input was invalid.
    	 * @param min The minimum valid input
    	 * @param max The maximum valid input
    	 * @return An integer in the range min..max
    	 */
    	public static final int readInteger(String prompt, String error, int min, int max) {
    		if (min >= max) {
    			return 0;   //Should not happen, but can if the client programmer is not paying attention
    		}
     
    		try {
    			int i = Integer.valueOf((readLine(prompt)));
    			if ((i < min) || (i > max)) {
    				System.out.println(error);
    				return readInteger(prompt, error, min, max);
    			}
    			return i;
    		} catch (NumberFormatException e) {
    			System.out.println(error);
    			return readInteger(prompt, error, min, max);
    		}
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input in a given range.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @param min The minimum valid input.
    	 * @param max The maximum valid input.
    	 * @return An integer in the range min..max
    	 */
    	public static final int readInteger(String prompt, int min, int max) {
    		return readInteger(prompt, DEFAULT_RETRY, min, max);
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input in a given range.
    	 *
    	 * @param min The minimum valid input.
    	 * @param max The maximum valid input.
    	 * @return An integer in the range min..max
    	 */
    	public static final int readInteger(int min, int max) {
    		return readInteger(DEFAULT_PROMPT, DEFAULT_RETRY, min, max);
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @param error The error message to inform the user that the input was invalid.
    	 * @return An integer
    	 */
    	public static final int readInteger(String prompt, String error) {
    		try {
    			return Integer.valueOf((readLine(prompt)));
    		} catch (NumberFormatException e) {
    			System.out.println("\n" + error);
    			return readInteger(prompt, error); 
    		}
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @return An integer
    	 */
    	public static final int readInteger(String prompt) {
    		return readInteger(prompt, DEFAULT_RETRY);
    	}
     
     
    	/**
    	 * Prompts the user for an Integer input.
    	 *
    	 * @return An integer
    	 */
    	public static final int readInteger() {
    		return readInteger(DEFAULT_PROMPT, DEFAULT_RETRY);
    	}
     
     
    	/**
    	 * Prompts the user for a Double input.
    	 * 
    	 * @param prompt The message asking for user input.
    	 * @param error The message to inform the user about invalid input.
    	 * @return A double
    	 */
    	public static final double readDouble(String prompt, String error) {
    		try {
    			return Double.valueOf((readLine(prompt)));
    		} catch (NumberFormatException e) {
    			System.out.println("\n" + error);
    			return readDouble(prompt, error);
    		}
    	}
     
    	/**
    	 * Prompts the user for a Double input.
    	 * 
    	 * @param prompt The message asking for user input.
    	 * @return A double
    	 */
    	public static final double readDouble(String prompt) {
    		return readDouble(prompt, DEFAULT_RETRY);
    	}
     
    	/**
    	 * Prompts the user for a Double input.
    	 * 
    	 * @return A double
    	 */
    	 public static final double readDouble() {
    		return readDouble(DEFAULT_PROMPT, DEFAULT_RETRY);
    	 }
     
     
    	/**
    	 * Prompts the user for a Float input.
    	 *
    	 * @param prompt The message asking for input.
    	 * @param error The message informing the user that the input was invalid.
    	 * @return A float
    	 */
    	public static final float readFloat(String prompt, String error) {
    		try {
    			return Float.valueOf((readLine(prompt)));
    		} catch (NumberFormatException e) {
    			System.out.println("\n" + error);
    			return readFloat(prompt, error);
    		}
    	}
     
     
    	/**
    	 * Prompts the user for a Float input.
    	 *
    	 * @param prompt The message asking for input.
    	 * @return A float
    	 */
    	public static final float readFloat(String prompt) {
    		return readFloat(prompt, DEFAULT_RETRY);
    	}
     
     
    	/**
    	 * Prompts the user for a Float input.
    	 *
    	 * @return A float
    	 */
    	public static final float readFloat() {
    		return readFloat(DEFAULT_PROMPT, DEFAULT_RETRY);
    	}
     
    	/**
    	 * Prompts the user for a String input at least minLength in size.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @param error The message informing the user about invalid input
    	 * @param minLength The minimum length of the string that is valid
    	 * @return A string minLength or greater in length
    	 */
    	public static final String readString(String prompt, String error, int minLength) {
    		String input = readLine(prompt);
    		if (input.length() < minLength) {
    			System.out.println("\n" + error);
    			return readString(prompt, error, minLength);
    		}
     
    		return input;
    	}
     
     
    	/**
    	 * Prompts the user for a String input. It will prompt again if the user does not enter anything
    	 *
    	 * @param prompt The message asking for user input.
    	 * @param error The message informing the user of invalid input
    	 * @return A String
    	 */
    	public static final String readString(String prompt, String error) {
    		String input = readLine(prompt);
    		if ((input.length() == 0) || (input == null) || (input.equals("\n"))) {
    			System.out.println("\n" + error);
    		}
     
    		return input;		
    	}
     
     
    	/**
    	 * Prompts the user for a String input.
    	 *
    	 * @param prompt The message asking for user input.
    	 * @return A String
    	 */
    	public static final String readString(String prompt) {		
    		return readString(prompt, DEFAULT_RETRY);
    	}
     
     
    	/**
    	 * Prompts the user for a String input.
    	 *
    	 * @return A String
    	 */
    	public static final String readString() {
    		return readString(DEFAULT_PROMPT, DEFAULT_RETRY);
    	}
     
     
     
    	/**
    	 *  Working method, used by every single method in this class.
    	 *  It uses the low level System.in.read() to build a StringBuffer containing
    	 *  the users input and traps the user in an loop until ENTER is pressed.
    	 *  In windows, the ENTER button returns /r/n which is dealt with in the loop.
    	 */
    	private static final String readLine(String prompt) {
    		System.out.print(prompt);
    		System.out.print("\n");
    		System.out.print(CONSOLE);
     
    		StringBuffer b = new StringBuffer();
    		while(true) {
    			try {
    				char c = (char) System.in.read();
    				b.append(c);
    				if (c == '\n') {
    					return b.toString().trim();    //Enter pressed
    				} else if (c == '\r') { }   //Windows carriage return \r is followed by \n so we ignore it and pick it up on the next loop
    			} catch (IOException e) { }     //Unsure what would cause this and what to do about it
    		}
    	}
    }

    This class promotes a DRY (Don't Repeat Yourself) approach to programming and is an excellent tool for new programmers to dive right into Java without getting bogged down with details. All of the methods in this class are static and final (so there is no constructor) and are guaranteed to return valid input by trapping the flow of control in a recursive loop. If the user enters invalid input it notifies the user of the error and prompts them again until the input is valid without you needing to write a single line of code. All of the methods are overloaded so you can define a custom prompt and error messages or you can let it use the default messages.

    WARNING. Please be aware that the class name 'Console' clashes with java.io.Console so you should avoid importing java.io.*;

    I have used this class in over 100 applications so I am pretty confident it is bug free. That being said I have not had the opportunity to test it on Linux or Macintosh so please tell me if you have any problems using it.

    Hoping you found this useful.


    Chris.
    Valid user input ChristopherLowe
    5
    1. JavaPF -
      Good post Chris. Thanks.
    1. 4845074 -
      Nice post.Very helpful.
    1. Dillibabu -
      smart post chris.. hats off to u
    1. ChristopherLowe -
      Big thank you to TJStrech for a bug fix in the readString function.

      Symptom
      Pressing enter without any input in the readString function causes the function to return instead of re-prompting.

      Cause
      Missing recursive call

      Fix
      Replace this function
      public static final String readString(String prompt, String error) {
        String input = readLine(prompt);
        if ((input.length() == 0) || (input == null) || (input.equals("\n"))) {
         System.out.println("\n" + error);
        }
       
        return input;  
       }

      with this
      public static final String readString(String prompt, String error) {
        String input = readLine(prompt);
        if ((input.length() == 0) || (input == null) || (input.equals("\n"))) {
         System.out.println("\n" + error);
         return readString(prompt, error);
        }
       
        return input;  
       }
    1. helloworld922 -
      Some minor suggestions:

      You might want to consider renaming the class to something like ConsoleTools. It's pretty bad to write a class with the same name as one in the Java API.

      I don't really see much point of declaring a static final method since static methods can't be overwritten anyways. The only thing it does is prevent you from overloading a static method with the same name and parameters in inheriting classes.

      You may want to look into using the Scanner class instead of trying to roll your own input reading method in readLine().

      Personally I have some slight reservations about using recursion here instead of using while loops. While loops can handle an infinite number of miss-inputs from the user, but with enough recursive calls the user can get your program to crash due to a stack overflow. In practice this probably won't happen, but just recognize that it could.

      If cross-platform support is your goal, in readLine() you may want to consider ending the line with the system line separator property. If you use the Scanner's nextLine() method it will do this for you.

      String lineTerminator = System.getProperty("line.separator");



      All in all, this is a good idea. Nicely done!