Zadanie 1
Napisz metodę, które jako parametr będzie przyjmowała napis i wypisywała na standardowe wyjście jego długość.
- Przekaż do tej metody null i zobacz jaki wyjątek został zgłoszony.
- Otocz wywołanie metody blokiem try-catch, przechwyć ten wyjątek i wypisz na standardowe wyjście ślad stosu wywołań z chwili zgłoszenia wyjątku.
- Bezpośrednio po wypisaniu jego śladu zgłoś obsługiwany wyjątek ponownie.
- Czy ślady stosu wypisane przez ciebie w bloku catch i przez maszynę wirtualną w chwili przerwania programu są takie same?
- Przed zgłoszeniem ponownie obsługiwanego wyjątku wykonaj na nim metodę fillInStackTrace().
- Zamiast zgłaszać ponownie obsługiwany wyjątek zgłoś nowy wyjątek klasy Exception. Zauważ, że wymaga to pewnej dodatkowej zmiany w kodzie.
- Dołącz obsługiwany wyjątek do nowo tworzonego wyjątku Exception jako przyczynę jego powstania.
Rozwiązanie (część 1)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) {
Zad1 z = new Zad1();
z.wypiszDługość(null);
}
}
Rozwiązanie (część 2)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) {
try {
Zad1 z = new Zad1();
z.wypiszDługość(null);
} catch (NullPointerException w) {
w.printStackTrace(System.out);
}
}
}
Rozwiązanie (część 3)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) {
try {
Zad1 z = new Zad1();
z.wypiszDługość(null);
} catch (NullPointerException w) {
w.printStackTrace(System.out);
throw w;
}
}
}
Rozwiązanie (część 5)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) {
try {
Zad1 z = new Zad1();
z.wypiszDługość(null);
} catch (NullPointerException w) {
w.printStackTrace(System.out);
w.fillInStackTrace();
throw w;
}
}
}
Rozwiązanie (część 6)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) throws Exception {
try {
Zad1 z = new Zad1();
z.wypiszDługość(null);
} catch (NullPointerException w) {
w.printStackTrace(System.out);
throw new Exception();
}
}
}
Rozwiązanie (część 7)
public class Zad1 {
void wypiszDługość(String s) {
System.out.println(s.length());
}
public static void main(String[] args) throws Exception {
try {
Zad1 z = new Zad1();
z.wypiszDługość(null);
} catch (NullPointerException w) {
throw new Exception(w);
}
}
}
Zadanie 2
Napisz trzy nowe wyjątki oraz metodę, która za każdym wywołanie będzie losowo zgłaszała jeden z nich.
- Otocz wywołanie tej metody instrukcją try-catch zawierającą po klauzuli catch dla każdego z wyjątków. Niech każda klauzula catch wypisuje który wyjątek złapała.
- Sprawdź co się stanie jeżeli zmienisz kod metody tak żeby przestała zgłaszać jeden z wyjątków, ale nadal będzie on wymieniony w klauzuli throws nagłówka metody. Czy metody wywołujące napisaną przez ciebie metodę, ale nie obsługujące tego wyjątku będą musiały nadal go wymieniać w swoich nagłówkach?
Rozwiązanie (część 1)
class MójWyjątekA extends Exception {}
class MójWyjątekB extends Exception {}
class MójWyjątekC extends Exception {}
public class Zad2 {
void losujWyjątek() throws MójWyjątekA, MójWyjątekB, MójWyjątekC {
java.util.Random r = new java.util.Random();
switch (r.nextInt(3)) {
case 0: throw new MójWyjątekA();
case 1: throw new MójWyjątekB();
case 2: throw new MójWyjątekC();
}
}
public static void main(String[] args) {
Zad2 z = new Zad2();
try {
z.losujWyjątek();
} catch (MójWyjątekA w) {
System.out.println(w.getClass());
} catch (MójWyjątekB w) {
System.out.println(w.getClass());
} catch (MójWyjątekC w) {
System.out.println(w.getClass());
}
}
}
Rozwiązanie (część 2)
Tak, będą musiały. W ten sposób możemy wymusić, by kod korzystający z tej metody był przygotowany na wyjątek, który może się pojawić w jej kolejnej wersji.
Zadanie 3
Napisz program sprawdzający, czy wyjątki zgłoszone w klauzuli catch mogą być obsłużone przez tą samą klauzulę lub jedną z pozostałych klauzul tej samej instrukcji try-catch.
Rozwiązanie
class MójWyjątek extends Exception {
public MójWyjątek() {
super();
}
public MójWyjątek(String s) {
super(s);
}
}
public class Zad3 {
public static void main(String[] args) throws Exception {
try {
throw new MójWyjątek("oryginalny");
} catch (MójWyjątek w) {
java.util.Random r = new java.util.Random();
switch (r.nextInt(3)) {
case 0: throw w;
case 1: throw new MójWyjątek("nowy");
case 2: throw new Exception();
}
} catch (Exception w) {}
}
}
Zadanie 4
Zmodyfikuj klasę ZwalnianieZasobów2, aby zwalnianie odbywało się w klauzuli finally. Sprawdź, czy rzeczywiście zasób jest zwalniany nawet jak blok try jest opuszczany przy pomocy instrukcji return,
break i continue.
Rozwiązanie
import java.io.IOException;
class InnyMożliwyWyjątek extends Exception {}
class Zasób3 {
Zasób3(int i) {
//...
}
void zarezerwuj() {}
void używaj() throws IOException {}
void innaNiebezpiecznaOperacja() throws InnyMożliwyWyjątek {}
void zwolnij() {}
}
public class ZwalnianieZasobów3 {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
Zasób3 z = new Zasób3(i);
try {
z.zarezerwuj();
//tu jest niebezpieczny kod
z.używaj();
z.innaNiebezpiecznaOperacja();
if (i == 3) continue;
if (i == 8) return;
//...
//zwalnianie zasobów
z.zwolnij();
} catch (IOException e) {
//obsługa wyjątku IOException
} catch (InnyMożliwyWyjątek w) {
//obsługa wyjątku InnyMożliwyWyjątek
} finally {
//zwalnianie zasobów
z.zwolnij();
}
}
}
}
Zadanie 5
Podczas rezerwowania i zwalniania zasobów zazwyczaj też może wystąpić wyjątek. Użyj pokazanej poniższej klasy Zasób3 i zmodyfikuj swoje rozwiązanie poprzedniego zadania, tak aby zawsze oba zasoby były zwalniane. Zadbaj żeby nie dochodziło do zaginięcia żadnych wyjątków. Możesz założyć, że wykonanie operacji zwolnij() na zamkniętym zasobie jest dozwolone.
class InnyMożliwyWyjątek extends Exception {}
class JeszczeInnyMożliwyWyjątek extends Exception {}
class Zasób3 {
Zasób3(int i) {
//...
}
void zarezerwuj() throws IOException {}
void używaj() throws IOException {}
void innaNiebezpiecznaOperacja() throws InnyMożliwyWyjątek, JeszczeInnyMożliwyWyjątek {}
void zwolnij() throws IOException {}
}
Rozwiązanie
public class ZwalnianieZasobów3 {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
Zasób3 z1 = new Zasób3(i);
Zasób3 z2 = new Zasób3(i);
try {
z1.zarezerwuj();
z2.zarezerwuj();
//tu jest niebezpieczny kod
z1.używaj();
z2.używaj();
z1.innaNiebezpiecznaOperacja();
z2.innaNiebezpiecznaOperacja();
if (i == 3) continue;
if (i == 8) return;
//...
//zwalnianie zasobów
z1.zwolnij();
z2.zwolnij();
} catch (IOException e) {
//obsługa wyjątku IOException
} catch (InnyMożliwyWyjątek w) {
//obsługa wyjątku InnyMożliwyWyjątek
} finally {
//obsługa wyjątków jest konieczna,
//żeby nie dopuścić do zaginięcia JeszczeInnyMożliwyWyjątek
try {
z1.zwolnij();
} catch (IOException e) {}
try {
z2.zwolnij();
} catch (IOException e) {}
}
}
}
}
Zadanie 6
Sprawdź, czy finally jest wykonywane pomimo wystąpienia wyjątku w bloku catch z tej samej instrukcji.
Rozwiązanie
public class Zas6 {
public static void main(String[] args) throws Exception {
try {
throw new Exception();
} catch (Exception e) {
System.out.println("catch");
throw new Exception();
} finally {
System.out.println("finally");
}
}
}