"The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in. We're computer professionals. We cause accidents." Nathaniel Borenstein, inventor of MIME, in: Programming as if People Mattered: Friendly Programs, Software Engineering and Other Noble Delusions, Princeton University Press, Princeton, NJ, 1991.
Valodā C kļūdu apstrādi bieži veica, deklarējot metodes, kuras atgriež veselus skaitļus. Ja veselais skaitlis bija negatīvs, tad varēja secināt, ka notikusi tā vai cita kļūda (varēja vienoties par to, kuram skaitlim - "kļūdas kodam" atbilst kura situācija).
int f(int arg1, int arg2, int& return_value) {
if (kautkasslikts) {
// atgriež "kļūdas kodu"
return -1;
}
else {
// izrēķina "īsto" atgriežamo vērtību
return_value = g(arg1, arg2);
}
// atgriež "sekmīgas izpildes kodu"
return 0;
}
Metodes f() izsaucējs pārbaudot atgriešanās kodu varēja uzzināt, vai return_value ir sekmīgi izrēķināts, vai nē. Tā kā valodā Java nav argumentu nodošanas "pēc references", tad atgriežamās vērtības nevar rakstīt argumentu sarakstā un šāda pieeja nav lietojama, toties tajā ir īpaši mehānismi izņēmumu apstrādei.
java.lang.Exception apraksta programmas izpildes laikā radušās kļūdas, kuras nav kritiskas, t.i. tās pēc vēlēšanās var apstrādāt un programmu turpināt. Situāciju piemēri, kad rodas izņēmumi:
Turpretī java.lang.Error klase definē nopietnas kļūdu situācijas, kuras programmētājam nav jācenšas apstrādāt pašam.
1 public class HelloWorld {
2 public static void main (String[] args) {
3 int i = 0;
4
5 String lines[] = {"AAA", "BBB", "CCC"};
6
7 while (i < 4) {
9 System.out.println(lines[i]);
10 i++;
11 }
12 }
13 }
Šī programma demonstrē izpildes laika kļūdu - mēģinājumu lasīt masīvā aiz pēdējā elementa. Šajā konkrētajā gadījumā kļūdu varētu novērst, ja 11. rindiņas vietā rakstītu pārbaudi, kura noskaidro īstās masīva beigas.
while (i < lines.length) { ... }
1 try {
2 // koda fragments, kurš varētu izraisīt noteikta veida izņēmumus
3 } catch (MyExceptionType myExcept) {
4 // šo izpilda, ja rodas MyExceptionType izņēmums
5 } catch (Exception otherExcept) {
6 // šo izpilda, ja rodas cits Exception tips
7 otherExcept.printStackTrace(System.out);
8 }
7. rindiņa šajā programmā drukā izsaukumu steku; līdzīgu izsaukumu steku drukā arī JVM, ja izņēmumu programmētājs neapstrādā un main() metode beidzas ar kļūdu.
1 try {
2 iegutResursu();
3 izmantotResursu();
4 } catch (MyException e) {
5 registretProblemu(e);
6 } finally {
7 atbrivotResursu();
8 }
finally blokā vadība nonāk ikreiz, kad no try bloka izpildās kaut viena rindiņa. Arī return vai break - ja tie mēģina izlēkt no try bloka - vispirms nodod vadību finally. Šādās situācijās programmas lasīšana ir apgrūtināta.
Ja izejot no catch vai finally izpildes vēl ir neapstrādāti izņēmumi (t.i. šie bloki paši rada izņēmumus), tad šie izņēmumi nonāk ārpus try-catch-finally konstrukcijas (pirms tam noteikti izpildās finally kods).
1 public class HelloWorld {
2 public static void main (String[] args) {
3 int i = 0;
4
5 String lines[] = {"AAA", "BBB", "CCC"};
6
7 while (i < 4) {
8 try {
9 System.out.println(lines[i]);
10 i++;
11 }
12 catch (ArrayIndexOutOfBoundsException e) {
13 System.out.println("Reset index 'i'");
14 i = 0;
15 } finally {
16 System.out.println("This line is always printed");
17 }
18 }
19 }
20 }

Labs stils nopietnās programmās prasa apstrādāt visus izņēmumus, kaut vai main() metodē tos noķerot, izdrukājot atbilstošu paziņojumu un pamēģinot atbrīvot programmas piesaistītos resursus.
Kļūdas arī ir Throwable, t.i. tās var noķert un apstrādāt. Bet, piemēram, steka pārpildīšanās vai "out-of-memory" nozīmē, ka programmas izpildei ir beigušies resursi. Šādā situācijā nav jēgas censties situāciju vēl tālāk pasliktināt, veicot papildu apstrādi un šādi pieprasot papildu resursus.
1 public void readDatabaseFile(String file)
2 throws FileNotFoundException, UTFDataFormatException {
3 // open file stream; may cause FileNotFoundException
4 FileInputStream fis = new FileInputStream(file);
5 // read a string from fis may cause UTFDataFormatException...
6 }
Pārdefinējošā metode (apakšklasē) var izraisīt izņēmumus, kuri ir apakšklases tiem izņēmumiem, kurus izraisa pārdefinējamā metode (virsklasē). T.i. apakšklases metodē nevar izraisīt izņēmumus, kuri ir "sliktāki" nekā deklarēts virsklasē.
1 public class TestA {
2 public void methodA() throws RuntimeException {
3 // do some number crunching
4 }
5 }
1 public class TestB1 extends TestA {
2 public void methodA() throws ArithmeticException {
3 // do some number crunching
4 }
5 }
1 public class TestB2 extends TestA {
2 public void methodA() throws Exception {
3 // do some number crunching
4 }
5 }
TestB2 nekompilējas, jo Exception nav apakšklase klasei RuntimeException.
1 import java.io.*;
2
3 public class TestMultiA {
4 public void methodA()
5 throws IOException, RuntimeException {
6 // do some IO stuff
7 }
8 }
1 import java.io.*;
2
3 public class TestMultiB1 extends TestMultiA {
4 public void methodA()
5 throws FileNotFoundException, UTFDataFormatException,
6 ArithmeticException {
7 // do some IO and number crunching stuff
8 }
9 }
1 import java.io.*;
2 import java.sql.*;
3
4 public class TestMultiB2 extends TestMultiA {
5 public void methodA()
6 throws FileNotFoundException, UTFDataFormatException,
7 ArithmeticException, SQLException {
8 // do some IO, number crunching, and SQL stuff
9 }
10 }
1 public class TestMultiB3 extends TestMultiA {
2 public void methodA() throws java.io.FileNotFoundException {
3 // do some file IO
4 }
5 }
TestMultiB1 kompilējas, jo abi pirmie izņēmumi ir apakšklases IOException.
TestMultiB2 nekompilējas - nevar pievienot jaunus - ar virsklases metodi nesavietojamus izņēmumus, piemēram, SQLException.
TestMultiB3 kompilējas, jo ir atļauts deklarēt mazāk izņēmumu nekā ir atbilstošajā virsklases metodē.
1 public class ServerTimedOutException extends Exception {
2 private int port;
3
4 public ServerTimedOutException(String message, int port) {
5 super(message);
6 this.port = port;
7 }
8
9 // Use getMessage method to get the reason the exception was made
10
11 public int getPort() {
12 return port;
13 }
14 }
1 public void connectMe(String serverName)
2 throws ServerTimedOutException {
3 int success;
4 int portToConnect = 80;
5
6 success = open(serverName, portToConnect);
7
8 if (success == -1) {
9 throw new ServerTimedOutException("Could not connect",
10 portToConnect);
11 }
12 }
1 public void findServer() {
2 try {
3 connectMe(defaultServer);
4 } catch (ServerTimedOutException e) {
5 System.out.println("Server timed out, trying alternative");
6 try {
7 connectMe(alternativeServer);
8 } catch (ServerTimedOutException e1) {
9 System.out.println("Error: " + e1.getMessage() +
10 " connecting to port " + e1.getPort());
11 }
12 }
13 }
public static void assert (boolean b, String location)
kurš "b==false" gadījumā veic nepieciešamos kļūdu reģistrācijas pasākumus ("error logging") un met izņēmumu, kurš aptur programmas tālāku izpildi. (JUnit piedāvā labāku pieņēmumu veidošanas karkasu jeb "framework")
Diskusiju tēmas