Vi kan kaste feilmeldinger:
throw new SomeException();
Vi kan fange opp feilmeldinger og gjøre noe med dem:
try {
// something
} catch (SomeException e) {
// when SomeException happens do this
}
Og vi kan ignorere feilmeldinger og kaste dem videre:
void someMethod() throws SomeException {}
En Exception er:
Å definere sin egen Exception er så lett som:
class MyException extends Exception {}
Så kan man kaste denne slik:
throw new MyException();
Men veldig ofte finnes det allerede en passende Exception:
Du kan også arve fra disse i stedet for fra Exception
Men for å skjønne Exceptions skikkelig er det viktig å skjønne funksjonskall. For hva skjer egentlig når vi kjører dette? Tegnetid!
public static void main(String[] args) {
a();
System.out.println("Bar!");
}
public static void a() {
b();
}
public static void b() {
c();
}
public static void c() {
System.out.println("Foo!");
}
La oss så legge til Exceptions:
class HelloException extends Exception {}
public static void main(String[] args) throws HelloException {
a();
System.out.println("Bar!");
}
public static void a() throws HelloException {
b();
}
public static void b() throws HelloException {
c();
}
public static void c() throws HelloException {
System.out.println("Foo!");
throw new HelloException();
}
RuntimeException er en variant av Exception som vanligvis representerer programmeringsfeil. Eksempler er:
Når man kaster en RuntimeException trenger man ikke være like nøye med å si hvordan de skal håndteres, for de skal jo vanligvis ikke oppstå(i motsetning til vanlige Exceptions).
Det forrige eksempelet med RuntimeException:
class ShouldNotHappenException extends RuntimeException {}
public static void main(String[] args) {
a();
System.out.println("Bar!");
}
public static void a() {
b();
}
public static void b() {
c();
}
public static void c() {
System.out.println("Foo!");
throw new ShouldNotHappenException();
}
For å håndtere feil har vi i Java try-catch-blokken:
try {
// something
} catch (SomeException e) {
// when SomeException happens do this
}
Ikke gjør dette:
try {
// something
} catch (Exception e) {}
Hvis du ikke kan/gidder gjøre noe for å fikse en feil, i alle fall gjør det lett for deg selv å se hva som gikk galt.
try {
// something with IO
} catch (IOException e) {
// Skriv ut informasjon om hvor feilen skjedde
e.printStackTrace();
// Avslutt programmet
System.exit(1);
}
Etter en try-catch-blokk kan man ha en finally-blokk, som kjøres uansett hva som skjer i try-catch-blokken:
try {
// something
} catch (SomeException e) {
// when SomeException happens do this
} finally {
// whatever happens do this
}
Den vanligste bruken av finally er å lukke filer:
Scanner sc = null;
try {
sc = new Scanner(new File("input.txt"));
// do something with sc
} catch (IOException e) {
// when we get an IOException do this
} finally {
if (sc != null) sc.close();
}
Men dette er jo noe herk...
Heldigvis fikk vi i Java 7 denne syntaksen som kalles try-with-resources:
try (Scanner sc = new Scanner(new File("input.txt"))) {
// do something with sc
// sc.close() will be called automatically
} catch (IOException e) {
// when we get an IOException do this
}
For at noe skal kunne brukes med try-with-resources må det bare implementere grensesnittet AutoCloseable
La oss så se på eksempelet vårt med try-catch:
class HelloException extends Exception {}
public static void main(String[] args) {
try {
a();
} catch (HelloException e) {
System.out.println("Woops! Exception happened!");
}
System.out.println("Bar!");
}
public static void a() throws HelloException {
b();
}
public static void b() throws HelloException {
c();
}
public static void c() throws HelloException {
System.out.println("Foo!");
throw new HelloException();
}
Og et enkelt eksempel med PrintWriter:
public static void main(String[] args) {
try (PrintWriter out = new PrintWriter("out.txt")) {
out.println("Hello world!");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// Hvis vi har mer kode her vil den bli kjørt,
// uavhengig av feil i koden over
}
Så noen detaljer dere kanskje ikke kommer til å trenge bruke med det første, men som kan være kjekt å vite om...
En try-blokk kan ha flere catch-blokker:
try (Scanner sc = new Scanner(new File("number.txt"))) {
someNumber += sc.nextInt();
} catch (FileNotFoundException e) {
System.out.println("Could not find number.txt!");
} catch (InputMismatchException e) {
System.out.println("First element was not a number!");
} catch (NoSuchElementException e) {
System.out.println("number.txt was too short!");
}
En catch-blokk kan ta flere feilmeldinger i samme blokk:
try (Scanner sc = new Scanner(new File("number.txt"))) {
someNumber += sc.nextInt();
} catch (FileNotFoundException e) {
System.out.println("Could not find number.txt!");
} catch (InputMismatchException | NoSuchElementException e) {
System.out.println("Bad content in number.txt!");
}
Feilmeldinger kan "pakkes inn" i andre feilmeldinger. Dette kalles exception chaining.
try (Scanner sc = new Scanner(new File("number.txt"))) {
someNumber += sc.nextInt();
} catch (FileNotFoundException
| InputMismatchException
| NoSuchElementException e) {
throw new IOException(e);
}
Videre lesning: