Learning objectives
Represent an algorithm as an ordered list of steps or as a flowchart, and explain how sequencing fixes the order in which the steps run
Describe how an IDE is used to write, compile and run a Java program, and state what the compiler checks before the program is allowed to run
Classify a fault as a syntax error, a logic error or a run-time error, and identify the likely cause of an ArithmeticException, a NullPointerException or an index-out-of-bounds exception
Choose test data, including boundary values, that exposes a logic error, and state the expected and actual output that reveal it
Key definitions
Algorithm
A finite list of exact instructions that, carried out in order, gets a job done or produces an answer. The same algorithm can be set out as numbered steps in plain words, as a flowchart or as Java code.
Sequencing
Carrying out the steps of an algorithm one at a time, in a fixed order. Each step finishes before the next begins, so swapping two steps can change the result.
Integrated development environment (IDE)
A program that brings together the tools for writing code: an editor, the compiler, a way to run the program and usually a debugger.
Compiler
The tool that checks Java source code against the rules of the language and, if it finds no errors, translates it into a form the computer can run. A program with a compile-time error cannot be run at all.
Syntax error
Code that is not legal Java: a missing semicolon, an unmatched brace, a value of the wrong type. The compiler refuses the program and reports the fault, so nothing runs until it is corrected. The AP course uses this name for every fault the compiler reports, type mismatches included.
Logic error
A fault in the thinking behind a program: the code is legal Java and runs to the end, yet it does the wrong thing, such as printing a wrong total or missing a case. No message appears, so it is found only by running tests whose correct results are already known.
Run-time error and exception
A run-time error is a failure that shows itself only while the program is executing; the program normally stops on the spot. An exception is a run-time error that Java raises itself: it meets a situation it cannot carry on from, one that depends on values the compiler never sees, such as an int being divided by zero, so it abandons the statement and reports what went wrong.
Explanation
Algorithms and sequencing. An algorithm is a finite list of exact instructions that gets a job done when the instructions are followed in order, and you were using algorithms long before you wrote a program: tying a shoelace, working out a long division on paper and paying at a self-service checkout each follow one. An algorithm can be written as a numbered list of steps in ordinary language or drawn as a flowchart, in which boxes hold the steps, a diamond holds a yes/no decision and arrows show the order. Sequencing means the steps are carried out one at a time, each finishing before the next begins, so the order is part of the algorithm. In Java, statements run from top to bottom. To swap the values of a and b you must write int temp = a; a = b; b = temp; — writing only a = b; b = a; copies b into a and then copies that same value straight back, so both variables end with the old value of b.
Write, compile, run. Java code can be typed in any text editor, but most programmers use an integrated development environment (IDE), which combines an editor with the tools to compile, run and debug a program. Before a program can run, the compiler reads the source code and checks it against the rules of Java: that each statement ends with a semicolon, that brackets and braces match, that every variable is declared before it is used, that each value fits the type of the variable it is stored in, and that every method call matches a method that exists. If it finds an error it reports it, usually with a line number, and no part of the program runs until every such error is fixed. Fixing one error can reveal others, because the compiler may stop checking after a badly broken line. A clean compile says only that the program obeys the rules of the language; it says nothing about whether the program does what was intended.
Three kinds of error. A syntax error breaks the rules of Java — for example int total = 0 with no semicolon, or int n = 4.5; which tries to store a double in an int — so the compiler reports it and the program never starts. A logic error is a fault in the thinking behind the program: it compiles and runs to the end but gives the wrong result, such as an average computed with integer division, or a test written age > 18 when the rule says 18 or over. Nothing warns you, so a logic error is found only by testing: running the program on data whose correct output you already know and comparing. A run-time error shows itself only while the program is executing, and the program normally stops on the spot. To classify a described fault, ask three questions in order: did it compile, did it stop part-way, did it finish with the wrong output?
Exceptions. An exception is a run-time error that Java raises itself when it meets a situation it cannot carry on from. The compiler had no chance of predicting it, because it depends on values that exist only while the program runs. Java stops at the statement that caused it and reports the name of the exception and the line number; statements before it have already run, and any output they produced stays on the screen. Three causes are worth knowing. An ArithmeticException is thrown when an int is divided by zero with / or %, as in total / count when count is 0. A NullPointerException is thrown when a method is called through a reference that holds null, such as s.length() when s is null, or names[1].length() when that element of a new String array was never assigned. An index-out-of-bounds exception is thrown when an index is below 0 or at least the length: ArrayIndexOutOfBoundsException for an array, and IndexOutOfBoundsException for the ArrayList methods get, set and remove. A String method such as substring throws a StringIndexOutOfBoundsException, which is one kind of IndexOutOfBoundsException, when an index is below 0 or greater than the length; an index equal to the length is allowed there, because it marks the position just after the last character.
Choosing test data. A test is useful only if you know the correct output before you run it. Good test data includes typical values, boundary values — the values at, just below and just above every limit in the specification — and unusual values such as 0, a negative number, an empty String or a list with a single element. Boundaries matter most, because a logic error very often sits on one: a method meant to return "pass" for a mark of 50 or more but written with mark > 50 gives the right answer for 30 and for 80, and fails only for exactly 50. When you report a test, give the input, the expected output and the actual output. The difference between the last two is the evidence of the fault, and it often points straight to the line that causes it.
Formulae
Syntax (compile-time) error → reported by the compiler → the program cannot run until it is fixed
Run-time error → the program compiles and starts, then halts part-way, often with an exception
Logic error → the program compiles and finishes, but the output is wrong → found only by testing
int divided by 0 with / or % → ArithmeticException · method call through null → NullPointerException · array or ArrayList index < 0 or ≥ length → index-out-of-bounds exception
Test data = typical values + boundary values (at, just below and just above each limit) + unusual values (0, negative, empty)
Worked examples
q: The method below is meant to return how many values in arr are at least limit: public static int countAtLeast(int[] arr, int limit) { int count = 0; for (int i = 1; i < arr.length; i++) { if (arr[i] > limit) { count++; } } return count; } Choose test data that exposes each fault, state the expected and actual results, and correct the method.
steps: The method compiles and runs to the end for any array, so any fault is a logic error. It can be found only by comparing expected with actual results.
Typical data first: for the array {3, 8, 9} and limit 5 the method should return 2, and it does return 2. The test passes, which shows that typical data can hide faults.
Test the start of the array: for {8, 1} and limit 5 the expected result is 1, because 8 is at least 5. The loop starts at index 1, so 8 is never examined and the method returns 0. Correction: start the loop at int i = 0.
Test the boundary of the condition: for {5, 5} and limit 5 the expected result is 2, because 5 is at least 5. The test 5 > 5 is false, so the method returns 0. Correction: compare with arr[i] >= limit.
Re-run every test on the corrected method: the results are 2, 1 and 2, all as expected. Keep the earlier tests too, because a later change could break a case that used to work.
In context
Payment and booking systems are tested at the exact limits of every rule — a balance of exactly zero, the last seat on a flight — because a fault that appears at one value can pass thousands of ordinary tests.
The wash cycle of a washing machine, a pilot’s pre-flight checklist and the steps of an online checkout are everyday algorithms: each is a fixed sequence, and doing two steps in the wrong order can spoil the result.
Common misconceptions
Students often think a program that compiles is correct. In fact the compiler checks only that the rules of Java are followed; a logic error compiles and runs without complaint and is found only by testing.
Students often call any crash a syntax error. In fact a syntax error stops the program from compiling, so it never starts; a program that starts and then halts has a run-time error.
Students often expect the compiler to catch a division by zero or an index that is too large. In fact these depend on values that exist only while the program runs, so they appear as exceptions at run time.
Students often test only typical values. In fact logic errors cluster at boundaries, so the values at, just below and just above each limit must be tested too.
Study tips
To classify an error, ask in order: does it compile, does it finish, is the output right? A no at the first question means a syntax error, at the second a run-time error, at the third a logic error.
When a question asks for test data, give the input, the expected output and the actual output of the faulty code; the mismatch is the evidence that earns the mark.
For an exception, name it and point to the exact cause: the divisor that can be 0, the reference that holds null or the index that reaches the length.
The compiler reports where it noticed a problem, which can be later than the mistake itself: a missing closing brace may be reported only at the end of the file.
Summary
An algorithm is an ordered sequence of steps; changing the order can change the result.
The compiler rejects any program that breaks the rules of Java, so a syntax error means nothing runs.
A run-time error halts a running program; ArithmeticException, NullPointerException and the index-out-of-bounds exceptions are run-time errors.
A logic error gives wrong output without any message and is exposed only by testing.
Test typical, boundary and unusual values, and compare the expected output with the actual output.
Check your understanding
Question 1: A program compiles, runs to the end and prints an average of 4.0 when the correct average is 4.5. What kind of error is this?
1. A run-time error
2. A logic error
3. A syntax error
Question 2: Which statement throws an ArithmeticException when count holds 0 and total holds 12?
1. int avg = total / count;
2. int half = count / 2;
3. int sum = total + count;
Question 3: A method must accept marks from 0 to 100 inclusive. Which single test value is a boundary value?
1. 57
2. −1000
3. 100
