Some things can fail and you do not know ahead of time. A user types a number into a form, a query finds no records, a call to an outside service times out. The code still has to keep running, so Apex gives you a way to say: try this, and if it goes wrong, do this other thing instead.
A try block holds the code that might fail. The moment anything inside it throws, Apex stops running the rest of the block and looks for a matching catch:
try {
Integer value = Integer.valueOf(userInput);
System.debug(value);
} catch (Exception e) {
System.debug('That was not a number');
}
If userInput holds 42, the debug prints 42 and the catch never runs. If it holds hello, Integer.valueOf throws, the debug line is skipped, and the catch runs.
Exception is the parent of every error type Apex knows about, so catch (Exception e) catches everything. You can also catch a more specific type when you only want to handle one case. Integer.valueOf throws a TypeException when the text is not a valid number, so catching that one type is enough to make the code safe:
try {
return Integer.valueOf(input);
} catch (TypeException e) {
return 0;
}
Code that does not handle failure leaves the user with a confusing error page. A well-placed try and catch lets the rest of the program keep going with a sensible default, and the user sees a clear result instead of a crash.