Skip to content
ExamSpine

Lesson 6.5

Validate before use

Part 6: Errors, testing and filesReading, about 6 min4 exercises in this lesson

Java answers can't run on Spine yet. You can still read Java, trace it, and put an answer's lines in order.

Validate before use

By the end of this you will be able to check a value before your program uses it, choose which checks a value needs, put them in the right order, and reject a bad value with a clear message.

Check first, then use

Validation means checking that a value is sensible before the program does anything with it. A value that fails is rejected: the program says what is wrong and does not use it.

There are two reasons to validate.

  • To stop an error. Turning a word into a whole number, or dividing a whole number by 0, stops a program that does not check first.
  • To stop nonsense. A game for 2 to 6 players can turn 40 into a whole number with no trouble, and no exception is raised. But 40 players makes no sense, and only a check written by you will notice.

The second reason is why catching exceptions is not enough. An exception tells you a line could not be carried out. It says nothing about a value that converts fine but is still wrong for your program.

Kinds of check

These are the checks you will use most. Each one asks one question about the value.

CheckThe question it asksA value that fails it
PresenceWas anything typed at all?an empty line
TypeIs it the right kind of value, such as a whole number?the word six where a whole number is needed
RangeIs the number between the smallest and the largest value allowed?40 for a game for 2 to 6 players
LengthDoes the text have an allowed number of characters?a name of 30 characters where at most 20 are allowed

A value usually needs more than one of them. Choose them by asking what the value will be used for, and what would go wrong if it were bad.

An example: a name for a badge

A badge printer reads a name. A name must have something in it, and at most 20 characters fit on the badge.

name = input()
if len(name) == 0:
    print("Type a name for the badge")
elif len(name) > 20:
    print("At most 20 characters fit")
else:
    print("Badge for " + name)
import java.util.Scanner;

public static void main(String[] args) {
    Scanner scanner
        = new Scanner(System.in);
    String name = scanner.nextLine();
    if (name.length() == 0) {
        System.out.println(
            "Type a name for the badge");
    } else if (name.length() > 20) {
        System.out.println(
            "At most 20 characters fit");
    } else {
        System.out.println(
            "Badge for " + name);
    }
}

The presence check and the length check each have their own message, so the user knows what to fix. Only a name that passes both reaches the line that uses it. The 20 itself is allowed, so the test that rejects is "more than 20", not "20 or more".

Order matters

Some checks only make sense once an earlier one has passed. A range check compares a number, so it needs a number. Text cannot be compared with a number, and trying is an error in both languages.

  • In Python, comparing the text "5" with the number 2 stops the program with TypeError: '>=' not supported between instances of 'str' and 'int'.
  • In Java, the same comparison with a String is a compile error, error: bad operand types for binary operator '>=', and nothing runs.

So for a value that should be a whole number in a range, the type check comes first. Do it the way the last lesson showed: try the conversion, and catch the exception if it fails. Only when the conversion has worked do you have a number, so the range check must only run then. One way is to put it inside the try, after the conversion line. A value that fails the type check is never range checked at all.

Check, or try and catch?

You now have two ways to protect a line that could fail.

  • Check first with an if, when you can test the value directly: whether a number is in a range, whether a text is empty or too long, whether a divisor is 0, whether an index is inside a list.
  • Try and catch, when the only way to find out is to attempt it. The simplest way to know whether some text is a whole number is to try to convert it.

Often a value needs both, as above: try and catch for the type, then an if for the range.

What validation cannot do

A valid value is not always the right one. If a player meant to type 4 and typed 5, the program accepts 5, because 5 is a whole number from 2 to 6. Validation can only reject values that cannot be right. It cannot know what the user meant.

Two common mistakes

  • Getting the edges of a range wrong. If 2 to 6 players are allowed, both 2 and 6 must pass. Write "2 or more" and "6 or less", not "more than 2" and "less than 6".
  • Checking the range of text that has not been converted yet. Convert it first, inside a try, and check the range only once you have a number.

Now try it yourself on the questions below.

Exercise 6.5.16.5.1 · Answer itValidate percentage

A program asks the user to type their percentage score for a test. Describe two checks the program should make on what the user types before it uses the value as a score. [2]

Exercise 6.5.26.5.2 · Write itIs it an hour?

An alarm app asks for the hour to ring, on a 24-hour clock. Write a function that checks the text the user typed before the app uses it as an hour.

  1. Return True when the text is a whole number from 0 to 23, and False for anything else (true and false in Java).
  2. Text that is not a whole number, such as a word, a decimal such as 7.5, or empty text, gives False. Your function must return, not stop with an error.
  3. A whole number outside 0 to 23, such as 24 or -1, gives False.
  4. When the text is a whole number, it is from -1000 to 1000, written with digits and maybe a minus sign in front. There are no spaces.

Only the value your function returns is checked.

def valid_hour(text: str) -> bool

Examples

Your function is tested on 12 cases: the 4 examples below, and 8 hidden ones that check the rules above.

  • valid_hour("7") should return True: a whole number in the range (rule 1)
  • valid_hour("seven") should return False: a word is not a whole number (rule 2)
  • valid_hour("24") should return False: one past the last hour (rule 3)
  • valid_hour("23") should return True: the last hour of the day (rule 1)

public static boolean validHour(String text)

Checking whether Java answers can run here.

Examples

Your function is tested on 12 cases: the 4 examples below, and 8 hidden ones that check the rules above.

  • validHour("7") should return true: a whole number in the range (rule 1)
  • validHour("seven") should return false: a word is not a whole number (rule 2)
  • validHour("24") should return false: one past the last hour (rule 3)
  • validHour("23") should return true: the last hour of the day (rule 1)
solution.pySolution.java

Exercise 6.5.36.5.3 · Write itCheck a nickname

A game shows each player's nickname above their character. Before it saves a nickname, it checks it. Write a function that returns whether a nickname is allowed.

  1. A nickname is allowed when it has from 3 to 12 characters and has no space in it.
  2. Return True when it is allowed and False when it is not (true and false in Java).
  3. The nickname is made of letters, digits and spaces only. It can be empty.

Only the value your function returns is checked.

def valid_nickname(name: str) -> bool

Examples

Your function is tested on 12 cases: the 4 examples below, and 8 hidden ones that check the rules above.

  • valid_nickname("Kai") should return True: exactly 3 characters, the shortest allowed (rule 1)
  • valid_nickname("Lumi2026Star") should return True: exactly 12 characters, the longest allowed (rule 1)
  • valid_nickname("Jo") should return False: only 2 characters (rule 1)
  • valid_nickname("Red Fox") should return False: the right length, but with a space (rule 1)

public static boolean validNickname(String name)

Checking whether Java answers can run here.

Examples

Your function is tested on 12 cases: the 4 examples below, and 8 hidden ones that check the rules above.

  • validNickname("Kai") should return true: exactly 3 characters, the shortest allowed (rule 1)
  • validNickname("Lumi2026Star") should return true: exactly 12 characters, the longest allowed (rule 1)
  • validNickname("Jo") should return false: only 2 characters (rule 1)
  • validNickname("Red Fox") should return false: the right length, but with a space (rule 1)
solution.pySolution.java

Exercise 6.5.46.5.4 · Write itMark checker

A teacher types test marks, one per line, and types end after the last one. Write a program that checks each line before using it, rejects the ones that cannot be marks, and adds up the rest.

  1. A line is a mark when it is a whole number from 0 to 100. Add each mark to the total and count it.
  2. For every other line, print Rejected: followed by the line, and carry on with the next line.
  3. When the line is exactly end, stop reading. Then print Accepted: followed by the number of marks, and on the next line Total: followed by their total.
  4. A line that is a whole number is from -1000 to 1000, written with digits and maybe a minus sign in front. Any other line is a word, a decimal such as 55.5, or empty. There are at most 30 lines before end.

In Python, convert each line with int and catch ValueError. In Java, convert it with Integer.parseInt and catch NumberFormatException.

Your program is run several times. Only what it prints is checked, and spaces at the end of a line are ignored.

Running Java here comes later. You can put this answer's lines in order instead. You can still write your Java answer (it stays while this page is open) and compare it with our worked solution. Or try this exercise in Python.

Examples

Your program is run 10 times: the 3 examples below, and 7 hidden ones that check the rules above. Only what it prints is checked.

  • two marks, both kept (rules 1 and 3)

    You type

    1. typed: 70
    2. typed: 85
    3. typed: end

    It prints

    Accepted: 2
    Total: 155
  • a word, and a whole number that is too big, are both rejected (rule 2)

    You type

    1. typed: 70
    2. typed: absent
    3. typed: 150
    4. typed: end

    It prints

    Rejected: absent
    Rejected: 150
    Accepted: 1
    Total: 70
  • 0 and 100 are marks; -1 and 101, just outside them, are not (rules 1 and 2)

    You type

    1. typed: 0
    2. typed: 100
    3. typed: -1
    4. typed: 101
    5. typed: end

    It prints

    Rejected: -1
    Rejected: 101
    Accepted: 2
    Total: 100
solution.pySolution.java