← Java tutorials

LESSON 28 / 40 · FREE TUTORIAL

Protect Your Program from Errors

Read abnormally, and let failure lead to clear results.

100–120 minutesThis chapter uses JDK 21 and does not require the preview function.Aggregation and procedure practice

WHAT YOU WILL MAKE

Make safe backpack administrator SafeInventory

The user inputs "a lot" and the program does not have to end immediately. You'll read exception clues, catch recoverable failures, check all conditions before writing to inventory, and provide actionable prompts. Prerequisites: methods, conditional judgments, Map and string conversion. Today, when the player inputs a lot of diamonds, the program will not explode on the spot like a creeper.

Before you start: It is recommended to complete Lessons 25–27 first

Type message and call location constitute fault clues
  1. Exception typeExplain which type of operation failed
  2. MessageGive specific input clues
  3. Source file line numberLocate your own code

01 / 15

Before starting: predict first, then let the program answer

This chapter uses JDK 21 and does not require the preview function. The story is borrowed from the block world, and the example runs on the ordinary Java console; if the values ​​​​and rules are course models, they will be clearly stated.

Each common example is a complete independent file, saved according to the file name marked on the box. Place each example in a different folder to avoid duplicate names of auxiliary classes. When the complete project is divided into sections, they are connected sequentially in the same file.

Terminal command: replace the Chinese placeholder with the actual file name and class name

javac -encoding UTF-8 ExampleFile.java
java ExampleClass
  • Prediction: Write the expected output first, or draw out the changes in references and data.
  • Verification: Check line by line after running, and then only change one condition.
  • Explanation: Explain whether the results come from Java rules, course contracts, or input data.

02 / 15

Exception reporting failed operation

An exception is not a notification that the programmer has been deducted points, but a fault report sent when it is discovered that the operation cannot be completed normally during runtime.

The stack trace lists the method call path. First look at the exception type and message, and then find the first line pointing to your source file.

Type message and call location constitute fault clues
  1. Exception typeExplain which type of operation failed
  2. MessageGive specific input clues
  3. Source file line numberLocate your own code

BadNumber.java · Intentional error example

public class BadNumber {
    public static void main(String[] args) {
        int amount = Integer.parseInt("Many");
        System.out.println(amount);
    }
}

03 / 15

try catch handles recoverable errors

Converting string to integer may fail. If the user can re-enter, catch the NumberFormatException and return an understandable result.

Dangerous operations are put into try and corresponding exceptions are handed over to catch
  1. tryOnly put operations that may fail
  2. catchHandling recoverable errors
  3. Return -1 on failureNot to be confused with legal positive numbers

L28Example02.java · Complete independent example

public class L28Example02 {
    static int parseAmount(String text) {
        if (text == null) return -1;
        try {
            int amount = Integer.parseInt(text.strip());
            return amount > 0 ? amount : -1;
        } catch (NumberFormatException error) { return -1; }
    }
    public static void main(String[] args) {
        System.out.println(parseAmount("12"));
        System.out.println(parseAmount("Many"));
    }
}

Output

12
-1

04 / 15

Capture specific exceptions

Although catching Exception saves words, it may mislead program errors into user input problems. Prioritize capturing specific types that you can handle explicitly.

Different faults require different repair solutions
  1. Specific exceptionNumberFormatException first
  2. Parent class exceptionIllegalArgumentException follows
  3. UnrecoverableKeep spreading, don’t pretend to be successful

L28Example03.java · Complete independent example

public class L28Example03 {
    public static void main(String[] args) {
        for (String text : new String[]{"Many", "80"}) {
            try {
                int amount = Integer.parseInt(text);
                if (amount < 1 || amount > 64)
                    throw new IllegalArgumentException(
                        "The single quantity must be within 1 to 64 between: " + amount);
                System.out.println("The quantity is legal=" + amount);
            } catch (NumberFormatException error) {
                System.out.println("Quantity must be an integer: " + text);
            } catch (IllegalArgumentException error) {
                System.out.println(error.getMessage());
            }
        }
    }
}

Output

Quantity must be an integer: Many
The single quantity must be within 1 to 64 between: 80

05 / 15

Ordinary verification does not need to throw exceptions

It is a common business situation for players to enter an empty name, and verification rules can be directly expressed using if. Exceptions are used for operations that cannot be completed normally; the choice depends on the calling contract, rather than treating exceptions as ordinary branching loops.

It is expected that you can choose to use if to handle the actual failure and then hand over the exception.
  1. Common verificationFor empty names, use if first
  2. Clear the contractWhat is the legal input?
  3. No side effectsOperate only after passing inspection

L28Example04.java · Complete independent example

public class L28Example04 {
    static boolean validName(String name) { return name != null && !name.isBlank(); }
    public static void main(String[] args) {
        System.out.println(validName(" "));
        System.out.println(validName(" Alex "));
    }
}

Output

false
true

06 / 15

throw reject bad parameters

If the method requires a single number of 1 to 64, check it at the entrance. throw hands the error to the caller rather than continuing to save bad data.

If the method finds that the contract is broken, it will be reported immediately.
  1. Entry CheckReject if the parameter is illegal
  2. throwLeave it to the caller for processing
  3. MessageInclusion range and received value

L28Example05.java · Complete independent example

public class L28Example05 {
    static void checkAmount(int amount) {
        if (amount < 1 || amount > 64)
            throw new IllegalArgumentException("The quantity should be 1 to 64: " + amount);
    }
    public static void main(String[] args) {
        try { checkAmount(-1); }
        catch (IllegalArgumentException e) { System.out.println(e.getMessage()); }
        checkAmount(64);
        System.out.println("64 Through");
    }
}

Output

The quantity should be 1 to 64: -1
64 Through

07 / 15

finally and resource cleanup

Finishing is performed along the control path. finally is suitable for ordinary closing; resources that need to be closed are given priority by using try-with-resources to avoid writing the success and failure branches separately.

When returning normally or throwing an exception, end along the control path
  1. finallyEnding on control path
  2. Automatic resource managementtry-with-resources
  3. Do not returnAvoid overwriting original exception or result

L28Example06.java · Complete independent example

import java.util.*;
public class L28Example06 {
    public static void main(String[] args) {
        try { Integer.parseInt("Many"); }
        catch (NumberFormatException e) { System.out.println("Requires integer"); }
        finally { System.out.println("This attempt ends"); }
        try (Scanner scanner = new Scanner("3")) {
            System.out.println(scanner.nextInt());
        }
    }
}

Output

Requires integer
This attempt ends
3

08 / 15

Detected and Unchecked Abnormalities

Checked exceptions are required by the compiler to be caught or declared in the method signature. Unchecked exceptions usually indicate that parameters or program state do not conform to the contract.

Compiler Requirements to Handle Partially Recoverable Failures
  1. IOExceptionCompiler requires processing or declaration
  2. RuntimeExceptionUnchecked exception
  3. Inspection methodDifferent does not mean different importance

L28Example07.java · Complete independent example

public class L28Example07 {
    static void read() throws java.io.IOException {
        throw new java.io.IOException("Demo read failed");
    }
    public static void main(String[] args) {
        try { read(); }
        catch (java.io.IOException e) { System.out.println(e.getMessage()); }
    }
}

Output

Demo read failed
Acceptance comparison table
CategoryExampleCommon processing
Detected exceptionIOExceptioncatch or throws
Unchecked exceptionIllegalArgumentExceptionModify parameter contract
Unchecked exceptionNumberFormatExceptionUser input can be captured

09 / 15

Custom abnormal expression field failure

When multiple backpack rules may fail, a custom exception lets the caller know explicitly that this is an issue with the inventory domain.

InventoryException indicates that the backpack operation failed
  1. InventoryExceptionExpressing a type of field failure
  2. extends ExceptionThis is designed as a checked exception
  3. CallerExplicitly choose how to restore

L28Example08.java · Complete independent example

class InventoryException extends Exception {
    InventoryException(String message) { super(message); }
}
public class L28Example08 {
    static int withdraw(int stock, int amount) throws InventoryException {
        if (stock < 0 || amount <= 0 || amount > stock)
            throw new InventoryException("Insufficient inventory");
        return stock - amount;
    }
    public static void main(String[] args) {
        try { withdraw(0, 1); }
        catch (InventoryException e) { System.out.println(e.getMessage()); }
    }
}

Output

Insufficient inventory

10 / 15

Error messages must be actionable

Good news allows users to know what happened and how to change it next, and also allows programmers to find corresponding operations.

Write clearly the input operation and legal range.
  1. What happenedAdd operation failed
  2. Which inputItem name or quantity
  3. Next stepProvide legal scope and correction suggestions
Acceptance comparison table
MessageProblemImprovement
ErrorNo contextQuantity must be an integer: many
failedNo operation nameFailed to add diamond: item name is empty
Wrong rangeNo legal scopeQuantity must be between 1 and 64: 80

11 / 15

Abnormal paths must also be tested

Only testing normal input is equivalent to only coloring the armor. True blast armor is meant to withstand impacts in the wrong path.

Successful capture, throwing and unchanged status must be accepted
  1. Normal operationIncrease in quantity
  2. Parsing failedChinese quantities cannot be converted to integers
  3. Status comparisonInventory will not be changed for any failure

L28Example10.java · Section 1/2, sequentially connected to the same file

import java.util.*;
public class L28Example10 {
    static void addItem(Map<String, Integer> inventory,
                        String item, int amount) {
        if (inventory == null)
            throw new IllegalArgumentException("Inventory cannot be null");
        if (item == null || item.isBlank())
            throw new IllegalArgumentException("Item name cannot be empty");
        if (amount < 1 || amount > 64)
            throw new IllegalArgumentException("The single quantity must be within 1 to 64 between: " + amount);
        String key = item.strip();
        Integer old = inventory.get(key);
        if (inventory.containsKey(key) && (old == null || old < 0))
            throw new IllegalArgumentException("The original inventory record is illegal: " + key);
        long total = (long) (old == null ? 0 : old) + amount;
        if (total > Integer.MAX_VALUE)
            throw new IllegalArgumentException("The cumulative inventory exceeds the upper limit of the integer: " + key);
        inventory.put(key, (int) total);
    }
    static String process(Map<String, Integer> inventory,
                          String item, String amountText) {
        if (item == null || item.isBlank()) return "Item name cannot be empty";
        if (amountText == null || amountText.isBlank()) return "Quantity cannot be empty";
        String key = item.strip();
        try {
            int amount = Integer.parseInt(amountText.strip());
            addItem(inventory, key, amount);
            return key + " Added successfully Quantity=" + inventory.get(key);

L28Example10.java · Paragraph 2/2, sequentially connected to the same file

        } catch (NumberFormatException error) {
            return "Quantity must be an integer: " + amountText;
        } catch (IllegalArgumentException error) {
            return error.getMessage();
        }
    }
    public static void main(String[] args) {
        Map<String, Integer> inventory = new HashMap<>(Map.of("diamond", 3));
        Map<String, Integer> before = new HashMap<>(inventory);
        System.out.println(process(inventory, "diamond", "-2"));
        System.out.println(inventory.equals(before));
    }
}

Output

The single quantity must be within 1 to 64 between: -2
true
Acceptance comparison table
EnterPathExpected
Diamond 3SuccessQuantity increased by 3
Lots of diamondsParsing failedPrompt integer data unchanged
Diamond -2Range failedPrompt 1 to 64 data remains unchanged
Empty name 5Verification failedPrompt name data remains unchanged
Diamond 64Boundary successAllow adding

12 / 15

Challenge Blueprint Security Backpack Manager

The challenge program is called SafeInventory. Each operation returns a friendly message and the inventory is modified only if all checks are passed.

Input processing: check first, then modify
  1. processVerify text and convert results
  2. addItemMaintain inventory rules
  3. Write at the endModify only after passing all verifications

Acceptance sequence

  • Diamond 3 was added successfully, and the cumulative quantity is 3.
  • The quantity text "many" prompt must be an integer, and the inventory remains unchanged.
  • Quantity-2 prompts a single range of 1 to 64, and the inventory remains unchanged.
  • Empty names are rejected before parsing and the inventory is unchanged.
  • Add diamond 64 again, and the total is 67; distinguish between the single upper limit and the cumulative inventory.

13 / 15

safety backpack program

Create a new SafeInventory.java, compile and run using Java 21.

Specific exceptions are specifically prompted.
  1. Single 1 to 64Quantity range per request
  2. Cumulative inventoryCan exceed 64, subject to the upper limit of int
  3. Friendly resultsSuccess or explicit rejection

SafeInventory.java · Section 1/2, sequentially connected to the same file

import java.util.*;
public class SafeInventory {
static void addItem(Map<String, Integer> inventory,
                    String item, int amount) {
    if (inventory == null)
        throw new IllegalArgumentException("Inventory cannot be null");
    if (item == null || item.isBlank())
        throw new IllegalArgumentException("Item name cannot be empty");
    if (amount < 1 || amount > 64)
        throw new IllegalArgumentException("The single quantity must be within 1 to 64 between: " + amount);
    String key = item.strip();
    Integer old = inventory.get(key);
    if (inventory.containsKey(key) && (old == null || old < 0))
        throw new IllegalArgumentException("The original inventory record is illegal: " + key);
    long total = (long) (old == null ? 0 : old) + amount;
    if (total > Integer.MAX_VALUE)
        throw new IllegalArgumentException("The cumulative inventory exceeds the upper limit of the integer: " + key);
    inventory.put(key, (int) total);
}
static String process(Map<String, Integer> inventory,
                      String item, String amountText) {
    if (item == null || item.isBlank()) return "Item name cannot be empty";
    if (amountText == null || amountText.isBlank()) return "Quantity cannot be empty";
    String key = item.strip();
    try {
        int amount = Integer.parseInt(amountText.strip());
        addItem(inventory, key, amount);
        return key + " Added successfully Quantity=" + inventory.get(key);

SafeInventory.java · Section 2/2, sequentially connected to the same file

    } catch (NumberFormatException error) {
        return "Quantity must be an integer: " + amountText;
    } catch (IllegalArgumentException error) {
        return error.getMessage();
    }
}
    public static void main(String[] args) {
        Map<String, Integer> inventory = new HashMap<>();
        System.out.println(process(inventory, "diamond", "3"));
        System.out.println(process(inventory, "diamond", "Many"));
        System.out.println(process(inventory, "diamond", "-2"));
        System.out.println(process(inventory, " ", "5"));
        System.out.println(process(inventory, "diamond", "64"));
        System.out.println("Final inventory=" + inventory.get("diamond"));
    }
}

Output

diamond Added successfully Quantity=3
Quantity must be an integer: Many
The single quantity must be within 1 to 64 between: -2
Item name cannot be empty
diamond Added successfully Quantity=67
Final inventory=67

14 / 15

Expansion tasks and clearance review

The job submits a successful path and at least three failed paths simultaneously. Write a sentence for each catch why it can be restored correctly.

Third-level tasks continue to strengthen error handling
  1. Path to successAt least one true addition
  2. Failure pathParsing, range, empty name
  3. catch reasonExplain why it can be restored

Third gear operation

  • Wooden Pickaxe: Read age safely, reject non-integer and negative numbers.
  • Iron Pickaxe: Analyze x y z coordinates, and retain the old position when any item is illegal.
  • Diamond Pickaxe: Record the number of occurrences of each error and output a diagnostic report at the end.
Acceptance comparison table
Self-evaluationCanStill need to practice
I can read abnormal clues□□
I will catch specific exceptions□□
I can test it unchanged after failure□□

15 / 15

Own acceptance record

Beautiful output is the starting point, and being able to explain boundaries is considered mastery. Select one case each from normal, borderline and error, write down your expectations before running, and leave evidence after running.

Leave a basis for judgment
CategoryThe operation you selectedCheck key points
NormalA common input or a successful actionIs the result consistent line by line?
BorderRange endpoints and adjacent valuesIs there one more step or one less thing?
ErrorIllegal quantity, missing object or bad dataWhether it is explicitly rejected and whether the status is maintained
  • Bug records: triggering conditions, actual phenomena, causes, and minimum repairs.
  • Illustrated record: describe the starting point, end point and meaning of each arrow.
  • Adaptation record: only change one rule, and modify expectations and tests at the same time.

TAKE IT WITH YOU

Take the lesson offline

The complete lesson, code, diagrams and exercises, in your preferred language.