Exception Handling
Quartz provides a robust exception handling system with Java-like syntax. Exceptions allow you to handle errors gracefully without crashing your program.
Basic Syntax
Try-Catch
Use try and catch to handle exceptions:
import system.io as io;
try {
// Code that might throw an exception
throw new Exception("Something went wrong!");
} catch (Exception e) {
// Handle the exception
io.out.println("Caught:", e.message);
}
Try-Catch-Finally
Use finally for cleanup code that always runs:
try {
// Risky operation
throw new RuntimeError("Operation failed");
} catch (RuntimeError e) {
io.out.println("Error:", e.message);
} finally {
// Always executed, even if exception occurred
io.out.println("Cleanup complete");
}
Throwing Exceptions
Throw a New Exception
throw new Exception("Error message");
throw new ValueError("Invalid input");
throw new RuntimeError("Operation failed");
throw new TypeError("Type mismatch");
throw new IndexError("Index out of bounds");
Throw a String
You can throw a string directly, which creates an Exception automatically:
throw "Simple error message";
// Equivalent to: throw new Exception("Simple error message");
Rethrow an Exception
try {
// ...
} catch (Exception e) {
// Log and rethrow
io.out.println("Logging error:", e.message);
throw e;
}
Built-in Exception Types
These exception types are available globally without importing:
| Exception Type | Use Case |
|---|---|
| `Exception` | Base exception type, catches all exceptions |
| `RuntimeError` | General runtime errors |
| `ValueError` | Invalid value or argument |
| `TypeError` | Type mismatch errors |
| `IndexError` | Index out of bounds |
| `NullError` | Null/undefined reference |
Exception Properties
When you catch an exception, you can access these properties:
try {
throw new ValueError("Invalid input");
} catch (ValueError e) {
io.out.println("Type:", e.type); // "ValueError"
io.out.println("Message:", e.message); // "Invalid input"
}
Catch Patterns
Catch Specific Type
try {
throw new IndexError("Out of bounds");
} catch (IndexError e) {
// Only catches IndexError
io.out.println("Index error:", e.message);
}
Catch Multiple Types
try {
// Some risky operation
} catch (ValueError e) {
io.out.println("Value error:", e.message);
} catch (TypeError e) {
io.out.println("Type error:", e.message);
} catch (Exception e) {
// Catch any other exception
io.out.println("Other error:", e.message);
}
Catch All Exceptions
try {
throw new RuntimeError("Something bad");
} catch (Exception e) {
// Exception catches all exception types
io.out.println("Caught:", e.type, "-", e.message);
}
The Finally Block
The finally block always executes, regardless of whether an exception was thrown or caught:
fn processFile() {
let file = openFile("data.txt");
try {
// Process file - might throw
processData(file);
} catch (Exception e) {
io.out.println("Error processing:", e.message);
} finally {
// Always close the file
closeFile(file);
io.out.println("File closed");
}
}
Best Practices
Be Specific
Catch specific exception types when possible:
// Good - specific handling
try {
parseNumber(input);
} catch (ValueError e) {
io.out.println("Invalid number format");
}
// Less good - catches everything
try {
parseNumber(input);
} catch (Exception e) {
io.out.println("Something went wrong");
}
Don't Swallow Exceptions
// Bad - exception is silently ignored
try {
riskyOperation();
} catch (Exception e) {
// Nothing here!
}
// Good - at least log it
try {
riskyOperation();
} catch (Exception e) {
io.out.println("Error:", e.message);
}
Use Finally for Cleanup
let resource = acquireResource();
try {
useResource(resource);
} finally {
releaseResource(resource); // Always runs
}
Fail Fast
Validate inputs early and throw meaningful exceptions:
fn divide(a: double, b: double) -> double {
if (b == 0) {
throw new ValueError("Division by zero");
}
return a / b;
}
Complete Example
import system.io as io;
import system.convert as conv;
fn parseAge(input: string) -> int {
let age = conv.toInt(input);
if (age < 0) {
throw new ValueError("Age cannot be negative");
}
if (age > 150) {
throw new ValueError("Age seems unrealistic");
}
return age;
}
fn main() {
io.out.println("Enter your age:");
let input = io.stdin.readln();
try {
let age = parseAge(input);
if (age < 18) {
io.out.println("You are a minor");
} else if (age < 65) {
io.out.println("You are an adult");
} else {
io.out.println("You are a senior");
}
} catch (ValueError e) {
io.out.println("Invalid age:", e.message);
} catch (Exception e) {
io.out.println("Unexpected error:", e.message);
} finally {
io.out.println("Thank you for using the program!");
}
}
main();
Exception Hierarchy
Exception (base)
├── RuntimeError
├── ValueError
├── TypeError
├── IndexError
└── NullError
Catching Exception will catch all exception types. More specific types only catch their own exceptions.