Java Programming

Chapter 3
Control Flow and Problem Solving

Certificate in Java-Python-Programming Languages
Java Programming   •   Certificate

Control Flow and Problem Solving

Introduction

A computer program is useful only when it can make decisions, repeat actions, and respond appropriately to different inputs. In Java, these capabilities are provided by control flow: the order in which statements are executed. Control flow transforms a list of instructions into an algorithm capable of solving a problem under varying conditions.

This chapter develops a disciplined approach to problem solving. It begins with algorithms and pseudocode, then introduces Boolean logic, selection statements, loops, input validation, and basic complexity awareness. The emphasis is not merely on memorising Java syntax, but on designing programs that are correct, readable, testable, and maintainable.

Learning Objectives

By the end of this chapter, you should be able to:

  • Describe an algorithm using structured English and pseudocode.
  • Apply Boolean expressions and logical operators correctly.
  • Use if, if-else, nested conditions, and switch statements.
  • Select appropriate for, while, and do-while loops.
  • Validate input and avoid common boundary errors.
  • Trace program execution using tables and test cases.
  • Recognise basic time-complexity patterns.
  • Design a complete solution to a structured programming problem.

1. Algorithms and Structured Problem Solving

An algorithm is a finite, ordered set of unambiguous steps that transforms input into an intended output. A sound algorithm has four important properties:

  1. Definiteness: every step has a clear meaning.
  2. Finiteness: the process eventually terminates.
  3. Input: it accepts zero or more values.
  4. Output: it produces at least one result or observable effect.

An algorithm should also be effective: each operation must be sufficiently basic to perform in a reasonable amount of time.

A reliable problem-solving process is:

  1. State the problem precisely.
  2. Identify inputs, outputs, and constraints.
  3. Divide the problem into smaller tasks.
  4. Develop an algorithm or pseudocode solution.
  5. Trace the algorithm with representative data.
  6. Translate it into Java.
  7. Test normal, boundary, and invalid cases.
  8. Review clarity, correctness, and efficiency.

Pseudocode

Pseudocode is an informal notation that expresses an algorithm without committing to a particular programming language. It is useful because it separates logical design from syntax.

Example: determine whether a number is positive, negative, or zero.

BEGIN
    READ number
    IF number > 0 THEN
        DISPLAY "Positive"
    ELSE IF number < 0 THEN
        DISPLAY "Negative"
    ELSE
        DISPLAY "Zero"
    END IF
END

Pseudocode should use consistent indentation and clear action words such as READ, CALCULATE, IF, REPEAT, and DISPLAY. It should describe the solution rather than imitate Java line by line.

2. Boolean Logic and Conditions

A Boolean expression produces one of two values: true or false. Conditions control whether a statement executes or whether a loop continues.

Java comparison operators include:

OperatorMeaning
==equal to
!=not equal to
>greater than
<less than
>=greater than or equal to
<=less than or equal to

For primitive values, == compares values. For objects such as String, use .equals() when comparing content:

if (name.equals("Amina")) {
    System.out.println("Name recognised");
}

The principal logical operators are:

OperatorMeaningExample
&&AND; both conditions must be trueage >= 18 && hasId
``
!NOT; reverses a Boolean value!isClosed

Truth Conditions

For P && Q, the result is true only when both P and Q are true. For P || Q, the result is false only when both are false. Java uses short-circuit evaluation: with &&, the second expression is not evaluated if the first is false; with ||, it is not evaluated if the first is true. This can improve efficiency and prevent errors.

if (value != 0 && 100 / value > 2) {
    System.out.println("Condition satisfied");
}

The division is evaluated only when value != 0 is true.

Precedence and Parentheses

Java evaluates arithmetic before comparisons and comparisons before logical operations. However, relying on memory of precedence can reduce readability. Use parentheses to make intent explicit:

if ((temperature < 0) || (temperature > 40 && warningEnabled)) {
    System.out.println("Extreme condition");
}

A common error is confusing assignment with comparison. The expression x = 5 assigns a value; x == 5 tests equality.

3. Selection Statements

Selection allows a program to choose among alternatives.

The if Statement

if (score >= 50) {
    System.out.println("Pass");
}

The block executes only when the condition is true. Braces are recommended even for one statement because they reduce maintenance errors.

The if-else Statement

if (balance >= withdrawal) {
    balance -= withdrawal;
} else {
    System.out.println("Insufficient funds");
}

Exactly one branch executes.

Multiple Alternatives

if (mark >= 70) {
    grade = 'A';
} else if (mark >= 60) {
    grade = 'B';
} else if (mark >= 50) {
    grade = 'C';
} else {
    grade = 'F';
}

Conditions are tested from top to bottom. Once one is true, the remaining branches are skipped. Therefore, ordering matters. If mark >= 50 appeared first, higher marks would incorrectly receive grade C.

Nested Selection

A selection statement may appear inside another selection statement, but excessive nesting can make code difficult to read. Complex conditions can often be simplified by using guard clauses or separate methods.

The switch Statement

switch is suitable when one expression is compared with several discrete values.

switch (option) {
    case 1:
        System.out.println("Create");
        break;
    case 2:
        System.out.println("View");
        break;
    case 3:
        System.out.println("Exit");
        break;
    default:
        System.out.println("Invalid option");
}

break prevents execution from falling through into the next case. The default branch handles values not explicitly listed. Modern Java also supports switch expressions, but the traditional form remains important for understanding control flow.

4. Repetition and Loops

Loops execute a block repeatedly. Every correctly designed loop requires:

  • an initial state;
  • a continuation condition;
  • an update that moves toward termination.

Failure to make progress can cause an infinite loop.

while Loop

A while loop tests its condition before executing its body. It is appropriate when the number of repetitions is not known in advance.

int count = 1;
while (count <= 5) {
    System.out.println(count);
    count++;
}

If the initial condition is false, the body executes zero times.

do-while Loop

A do-while loop executes its body at least once because the condition is tested afterward.

int choice;
do {
    System.out.println("1. Continue  0. Exit");
    choice = scanner.nextInt();
} while (choice != 0 && choice != 1);

This structure is useful for menus and input validation.

for Loop

A for loop is usually appropriate when the number of repetitions is controlled by a counter.

for (int i = 1; i <= 10; i++) {
    System.out.println(i);
}

Its three parts are initialisation, condition, and update. The equivalent logic can be expressed with a while loop, but for communicates counting intent more clearly.

Nested Loops

A loop inside another loop is a nested loop.

for (int row = 1; row <= 3; row++) {
    for (int column = 1; column <= 4; column++) {
        System.out.print("* ");
    }
    System.out.println();
}

The inner loop runs four times for each of three outer iterations, producing 12 executions of its body.

break and continue

break exits the nearest loop immediately. continue skips the remainder of the current iteration and proceeds to the next iteration.

These statements have legitimate uses, such as stopping a search when a target is found. However, excessive use can obscure the loop’s termination logic. A clear condition is generally preferable.

5. Input Validation

Input validation checks whether data is acceptable before processing it. Validation is different from error handling: validation concerns whether input satisfies rules, while error handling concerns unexpected failures such as an input type mismatch or unavailable file.

Suppose a percentage must lie between 0 and 100 inclusive. The valid condition is:

percentage >= 0 && percentage <= 100

The inclusive boundaries are important. A value of 0 or 100 is valid, while −1 and 101 are invalid.

int percentage;
do {
    System.out.print("Enter percentage (0-100): ");
    percentage = scanner.nextInt();
} while (percentage < 0 || percentage > 100);

The invalid condition is the logical opposite of the valid condition. Applying De Morgan’s laws:

  • !(P && Q) is equivalent to !P || !Q.
  • !(P || Q) is equivalent to !P && !Q.

Thus, “not between 0 and 100” becomes “less than 0 or greater than 100.”

Validation should address:

  • Type: Is the input an integer, decimal, or text value?
  • Range: Is it within acceptable limits?
  • Format: Does it follow the required structure?
  • Consistency: Does it agree with related data?
  • Security: Could it contain malicious or unsafe content?

Programs should communicate the problem clearly and avoid silently changing user input.

6. Tracing and Testing Control Flow

A trace table records variable values at significant points in execution. Consider:

int total = 0;
for (int i = 1; i <= 4; i++) {
    total += i;
}
Iterationi before bodytotal after body
111
223
336
4410

After the fourth update, i becomes 5, the condition i <= 4 is false, and the loop terminates.

Good tests include:

  • Typical values: ordinary valid input.
  • Boundary values: values exactly at limits.
  • Just outside boundaries: values that should be rejected.
  • Empty or zero cases: where meaningful.
  • Large values: to expose performance or overflow problems.
  • Invalid types or formats: to test robustness.

A program that works for one example is not necessarily correct. Testing should be systematic and based on the input domain.

7. Basic Complexity Awareness

Algorithmic complexity describes how resource use grows as input size increases. Let n represent the number of input elements. The notation O(1) describes constant work, O(n) linear work, and O(n²) quadratic work.

Examples:

System.out.println(values[0]);       // O(1)

Accessing one known array element takes constant time.

for (int i = 0; i < n; i++) {
    System.out.println(values[i]);   // O(n)
}

The loop body executes approximately n times.

for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
        count++;
    }
}

The inner statement executes n × n = n² times, so the running time is O(n²). Complexity analysis ignores constant factors and lower-order terms when describing growth. It does not predict exact execution time, which also depends on hardware, implementation, and data.

A nested loop is not automatically O(n²): if the inner loop performs a constant number of operations, the total may still be O(n). Complexity must be inferred from actual bounds and dependencies.

8. Worked Example: A Menu-Driven Temperature Analyzer

Problem

Design a program that repeatedly accepts temperatures, counts how many are below freezing, and reports the average. The user enters -999 to stop. The sentinel should not be included in the calculations.

Analysis

Inputs are temperatures in degrees Celsius. The sentinel is −999. Outputs are the number of readings, the number below 0 °C, and the average. The program must handle the case in which no readings are entered, avoiding division by zero.

Pseudocode

SET count to 0
SET belowFreezing to 0
SET total to 0
READ temperature
WHILE temperature is not -999
    ADD temperature to total
    INCREMENT count
    IF temperature < 0 THEN
        INCREMENT belowFreezing
    END IF
    READ temperature
END WHILE
IF count > 0 THEN
    SET average to total / count
    DISPLAY count, belowFreezing, average
ELSE
    DISPLAY "No readings entered"
END IF

Java Implementation

import java.util.Scanner;

public class TemperatureAnalyzer {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        final int SENTINEL = -999;
        int count = 0;
        int belowFreezing = 0;
        double total = 0;

        System.out.print("Enter temperature (-999 to stop): ");
        int temperature = scanner.nextInt();

        while (temperature != SENTINEL) {
            total += temperature;
            count++;

            if (temperature < 0) {
                belowFreezing++;
            }

            System.out.print("Enter temperature (-999 to stop): ");
            temperature = scanner.nextInt();
        }

        if (count > 0) {
            double average = total / count;
            System.out.println("Readings: " + count);
            System.out.println("Below freezing: " + belowFreezing);
            System.out.println("Average: " + average + " °C");
        } else {
            System.out.println("No readings entered.");
        }
    }
}

The sentinel is tested before it is added, so it does not contaminate the total or count. If the inputs are 4, −2, 6, and −999, then the count is 3, the below-freezing count is 1, and the average is (4 − 2 + 6) ÷ 3 = 8 ÷ 3 ≈ 2.67 °C. The algorithm is O(n), where n is the number of valid readings, and uses O(1) additional storage.

9. Applied Case: Student Assessment Processing

This is an illustrative case.

Background

A training centre needs a small Java program to process assessment marks. Each mark must be from 0 through 100. The program should classify each valid mark as Distinction, Pass, or Fail and calculate the average of all marks.

Problem

The first design accepted any integer and classified marks using conditions in the order mark >= 50, mark >= 70, and otherwise. This produced incorrect results because distinctions were classified as passes. It also divided by zero when the user entered no marks.

Analysis and Solution

The corrected design validates the range, checks the highest classification first, and calculates an average only when the count is positive:

if (mark < 0 || mark > 100) {
    System.out.println("Invalid mark");
} else {
    if (mark >= 70) {
        System.out.println("Distinction");
    } else if (mark >= 50) {
        System.out.println("Pass");
    } else {
        System.out.println("Fail");
    }
}

The program should test 0, 49, 50, 69, 70, 100, −1, and 101. These tests examine both classification boundaries and validation boundaries.

Outcome and Learning Points

The revised design is correct because conditions are ordered from most specific or restrictive to less restrictive, invalid input is rejected before classification, and the empty-data case is handled explicitly. The case demonstrates that control flow is a design issue, not merely a syntax issue.

10. Best Practices and Common Errors

  • Use braces consistently.
  • Give Boolean variables names such as isValid or hasPermission.
  • Avoid deeply nested conditions where a method can clarify intent.
  • Use named constants for sentinel values and fixed limits.
  • Check loop boundaries carefully: i < n and i <= n are not equivalent.
  • Initialise counters and accumulators before loops.
  • Ensure every loop can make progress toward termination.
  • Avoid comparing floating-point values for exact equality when approximation is required.
  • Keep input, processing, and output responsibilities conceptually separate.
  • Test boundaries and invalid values, not only typical examples.

Control flow also has professional and ethical implications. A faulty eligibility condition may unfairly deny access to a service; an incorrect validation rule may accept unsafe data. Developers should document assumptions, preserve auditability, protect personal information, and test decisions that affect users. AI-assisted code generation can produce plausible but incorrect conditions, so generated code must be reviewed, traced, tested, and understood before use.

Chapter Summary

Control flow determines the execution order of a Java program. Algorithms provide finite, unambiguous procedures for solving problems, while pseudocode allows those procedures to be designed independently of language syntax. Boolean expressions and logical operators form the basis of decisions and loop conditions. Java selection statements include if, if-else, chained conditions, and switch. The while, do-while, and for statements support repetition, each being appropriate in different circumstances.

Reliable programs validate input, handle boundary and empty cases, and use trace tables and systematic tests to reveal errors. Basic complexity awareness distinguishes constant, linear, and quadratic growth. Good solutions combine correctness, clarity, termination, validation, maintainability, and responsible treatment of users and data.

Key Terms

Algorithm: A finite sequence of unambiguous steps for solving a problem.

Boolean expression: An expression whose value is true or false.

Control flow: The order in which program statements execute.

Condition: A Boolean expression used to control a decision or loop.

Counter: A variable used to count repetitions or items.

Decision: A control structure that selects among alternatives.

Do-while loop: A loop that executes its body at least once before testing its condition.

Iteration: One execution of a loop body.

Loop: A control structure that repeats statements.

Nested loop: A loop placed inside another loop.

Pseudocode: Language-independent notation for expressing an algorithm.

Sentinel: A special value that signals termination of input.

Short-circuit evaluation: Evaluation that stops when the result is already determined.

Selection: Control flow that chooses a branch based on a condition.

Trace table: A table recording variable values during execution.

Validation: Checking whether input satisfies specified requirements.

While loop: A loop that tests its condition before each execution.

Time complexity: A description of how running time grows with input size.

Review Questions

Short Answer Questions

  1. What are the essential characteristics of an algorithm?
  2. Why should .equals() generally be used to compare the contents of Java strings?
  3. What is the difference between a while loop and a do-while loop?
  4. Why is input validation important?
  5. What does O(n) indicate about an algorithm’s growth?

Long Answer Questions

  1. Explain the problem-solving process from problem statement to tested Java implementation.
  2. Compare if-else chains and switch statements, including suitable uses for each.
  3. Explain short-circuit evaluation and provide a situation in which it prevents an error.
  4. Describe how boundary-value testing can be applied to a mark-validation program.
  5. Explain how nested loops influence time complexity, using examples.

Analytical / Application Questions

  1. Design pseudocode and Java logic for a program that accepts positive integers until zero is entered, then reports the largest value. Address the case where no positive number is entered.
  2. A loop begins with i = 1, continues while i <= n, and increases i by 2. Determine its growth order and explain how you would test its boundary behaviour.
  3. Review a menu program that accepts options 1–4 but uses only if (option > 1 && option < 4). Identify the valid option incorrectly excluded and propose a corrected condition.

Multiple Choice Questions with Answers

Question 1

Which Java operator tests whether two primitive values are equal?

A. =

B. ==

C. !=

D. equals

Correct Answer: B. ==

Question 2

Which loop guarantees that its body executes at least once?

A. for

B. while

C. do-while

D. enhanced for

Correct Answer: C. do-while

Question 3

What is the result of true && false?

A. true

B. false

C. 0

D. An error

Correct Answer: B. false

Question 4

Why is break commonly used in a traditional switch statement?

A. To repeat the case

B. To prevent fall-through

C. To validate input

D. To compare strings

Correct Answer: B. To prevent fall-through

Question 5

Which condition accepts an integer from 0 through 100 inclusive?

A. x > 0 && x < 100

B. x >= 0 || x <= 100

C. x >= 0 && x <= 100

D. x < 0 && x > 100

Correct Answer: C. x >= 0 && x <= 100

Question 6

What is the basic time complexity of a single loop that executes once for each of n input elements?

A. O(1)

B. O(log n)

C. O(n)

D. O(n²)

Correct Answer: C. O(n)

Question 7

In the temperature example, why is the sentinel excluded from the total?

A. It is read after the loop

B. It is tested before being processed

C. It is always positive

D. It is converted to a string

Correct Answer: B. It is tested before being processed

Question 8

Which statement about an if-else-if chain is correct?

A. All true branches execute

B. Only the last branch executes

C. The first true branch executes and the rest are skipped

D. The conditions are evaluated randomly

Correct Answer: C. The first true branch executes and the rest are skipped

Question 9

What does continue do in a loop?

A. Terminates the entire program

B. Exits the nearest loop

C. Skips the rest of the current iteration

D. Restarts the Java virtual machine

Correct Answer: C. Skips the rest of the current iteration

Question 10

If a nested loop executes n times for every one of n outer iterations, what is the basic time complexity?

A. O(1)

B. O(n)

C. O(log n)

D. O(n²)

Correct Answer: D. O(n²)

Java Programming
Chapter 3 of 15