Abstractions in computer science hide details to manage complexity. Procedural abstraction mean breaking a program into pieces, implementing each piece as a procedure (also known as a method or a function), and combining calls to the procedures to form the overall program.
Procedural abstraction makes programs easier to write because:
- The programmer does not have to keep the entire program in their head at one time.
- Small pieces of code can be tested immediately after they are completed. Errors can be fixed while code is still fresh in the programmer’s mind.
- The amount of code being tested and debugged at one time is small.
- Different programmers can work on different parts of the program at the same time. Each programmer can test their code independently of other programmers.
Commonly used abstractions include:
- Variables
- Procedures (see details below)
- Parameters
- Classes (in object oriented languages such as Java)
- Lists
- Strings
Example: Statistics from test scores
Consider the problem of accepting test scores from a user then calculating and displaying statistics about the scores. Statistics include the mean and the standard deviation.
Score (0-100): 50
Score (0-100 or -1 when done): 75
Score (0-100 or -1 when done): 100
Score (0-100 or -1 when done): -1
Mean : 75
Std Dev: 20.41
The above shows a sample run of the program. The values 50
, 75
, 100
, and -1
(a sentinel) are input by the user. Everything else shown is displayed by the program.
getTestScores
method
public static ArrayList<Integer> getTestScores()
{
final int MIN_SCORE = 0;
final int MAX_SCORE = 100;
final int INVALID_VALUE = -1;
Scanner fromKeyboard = new Scanner(System.in);
System.out.print("Score (" + MIN_SCORE + "-" + MAX_SCORE + "): ");
int score = asInt(fromKeyboard.nextLine(), INVALID_VALUE);
while(score < MIN_SCORE || score > MAX_SCORE)
{
System.out.println("Invalid score");
System.out.print("\nScore (" + MIN_SCORE + "-" + MAX_SCORE + "): ");
score = asInt(fromKeyboard.nextLine(), INVALID_VALUE);
}
ArrayList<Integer> scores = new ArrayList<Integer>();
while(score >= MIN_SCORE && score <= MAX_SCORE)
{
scores.add(score);
System.out.print("Score (" + MIN_SCORE + "-" + MAX_SCORE + " or -1 when done): ");
score = asInt(fromKeyboard.nextLine(), INVALID_VALUE);
}
fromKeyboard.close();
return scores;
}
Accepting all and only valid test scores from the user is more complicated than it may at first appear. Invalid scores must be rejected. At least 1 valid score must be accepted. The user must be able to indicate when they are done entering scores.
Each significant task in a program should be written as a procedure (often called a method or a function). The procedure should be testable before more of the program is written.
The getTestScores
method handles all of the requirements and returns a list of valid test scores entered by the user. The method does not calculate or display statistics about that scores. Calculating statistics about the scores should be done in separate methods. Displaying the calculated statistics should be done in a separate method.
Testing getTestScores
public static void main(String[] args)
{
System.out.println(getTestScores());
}
The getTestScores
method can be tested by calling the method and printing the returned list.
If the user enters: 50
, 75
, 100
, and -1
the test code prints: [50, 75, 100]
getTestScores
as an abstraction
Once the getTestScores
method has been tested, and any errors fixed, it becomes an abstraction. Whenever we need to accept test scores from the user, we can call the getTestScores
method without worrying about how the code inside works.
Many development environments support collapsing methods so that only the method header is visible (and the code inside the method is hidden). This is a visual represntation of abstraction.
getMean
method
public static double getMean(ArrayList<Integer> scores)
{
int sum = 0;
for(int score : scores)
sum += score;
return sum / (double) scores.size();
}
The getMean
method accepts scores
, a list of test scores, as a parameter. The method calculates and returns the mean of the scores.
The getMean
method does not call the getTestScores
method. Combining calls to the methods to form the overall program is handled later.
Testing getMean
public static void main(String[] args)
{
ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(50);
scores.add(75);
scores.add(100);
System.out.println(getMean(scores)); // 75.0
}
The getMean
method can be tested by
- creating a list that contains specific scores,
- calling
getMean
and passing the list as an argument, and - printing the returned value.
The expected value (75.0
) is shown as a comment.
The test code does not require user input. This allows the test to be quickly repeated if an error is detected and corrected.
Additional test cases should be used to determine that getMean
works correctly; however, that is beyond the scope of this page.
getMean
as an abstraction
Once the getMean
method has been determined to work, it can be called without worrying about how the code inside works. This will be useful when calculating the standard deviation.
getStandardDeviation()
method
public static double getStandardDeviation(ArrayList<Integer> scores)
{
final double mean = getMean(scores);
double sumOfSquares = 0;
for(int score : scores)
sumOfSquares += Math.pow(score - mean, 2);
return Math.sqrt(sumOfSquares / scores.size());
}
Calculating the standard deviation requires calculating the mean. The getMean
method is called to calculate the mean. When calling getMean
within getStandardDeviation
, it is not necessary to remember how the code inside getMean
works. This is abstraction (hiding details that are not relevant right now).
Testing getStandardDeviation()
public static void main(String[] args)
{
ArrayList<Integer> scores = new ArrayList<Integer>();
scores.add(50);
scores.add(75);
scores.add(100);
System.out.println(getStandardDeviation(scores)); // 20.412
}
The getStandardDeviation
method is tested using the same approach as the getMean
test.
main()
method
public static void main(String[] args)
{
ArrayList<Integer> scores = getTestScores();
DecimalFormat formatter = new DecimalFormat("#.##");
System.out.println();
System.out.println("Mean : " + formatter.format(getMean(scores)));
System.out.println("Std Dev: " + formatter.format(getStandardDeviation(scores)));
}
The main
method is responsible for the overall program. It calls the other methods and handles the return values.
The main
method here also uses a DecimalFormat
object to format the output. In this case, the numbers are rounded to 2 decimal places.
While writing the main
method, it is not necessary to worry about how the code inside each other method works. All that is necessary is understanding how each method is called and what each method does (not how it does it).
Complete code
The main
method in the above file includes the test code commented out.
The file also includes the asInt
method. asInt
was called within getTestScores
but not otherwise shown. Input validation as String discusses asInt
in detail.
Help & comments
Get help from AP CS Tutor Brandon Horn