Personal tools

PO Wyjątki - ćwiczenia

From Studia Informatyczne

<<< Powrót do przedmiotu Programowanie obiektowe

<<< Powrót do wykładu Wyjątki

Spis treści

Zadanie 1

Napisz metodę, która jako parametr będzie przyjmowała napis i wypisywała na standardowe wyjście jego długość.

  1. Przekaż do tej metody null i zobacz, jaki wyjątek został zgłoszony.
  2. 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.
  3. Bezpośrednio po wypisaniu jego śladu zgłoś obsługiwany wyjątek ponownie.
  4. Czy ślady stosu wypisane przez ciebie w bloku catch i przez maszynę wirtualną w chwili przerwania programu są takie same?
  5. Przed zgłoszeniem ponownie obsługiwanego wyjątku wykonaj na nim metodę fillInStackTrace().
  6. Zamiast zgłaszać ponownie obsługiwany wyjątek, zgłoś nowy wyjątek klasy Exception. Zauważ, że wymaga to pewnej dodatkowej zmiany w kodzie.
  7. 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ęść 4)

Tak

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.

  1. Otocz wywołanie tej metody instrukcją try-catch zawierającą po jednym bloku catch dla każdego z wyjątków. Niech każdy blok catch wypisuje, który wyjątek złapała.
  2. 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 blokach catch mogą być obsłużone przez ten sam blok lub jeden z pozostałych bloków 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

W poniższym przykładzie w bloku try jest pięć instrukcji. Każda z nich może zgłosić taki sam wyjątek. Zaproponuj rozwiązanie, które w kodzie obsługi wyjątku pozwoli sprawdzić, w której instrukcji on wystąpił.

public class Zad4 {
  void możeZgłosićWyjątek() throws Exception {
    if (new java.util.Random().nextInt(5) == 0)
      throw new Exception();
  }
 
  public static void main(String[] args) {
    Zad4 z = new Zad4();
    try {
      z.możeZgłosićWyjątek();
      z.możeZgłosićWyjątek();
      z.możeZgłosićWyjątek();
      z.możeZgłosićWyjątek();
      z.możeZgłosićWyjątek();
    } catch (Exception e) {
      //jakiś kod obsługi
    }
  }
}

Rozwiązanie

public class Zad4 {
  void możeZgłosićWyjątek() throws Exception {
    if (new java.util.Random().nextInt(5) == 0)
      throw new Exception();
  }
 
  public static void main(String[] args) {
    Zad4 z = new Zad4();
    int i = 1;
    try {
      z.możeZgłosićWyjątek();
      i++;
      z.możeZgłosićWyjątek();
      i++;
      z.możeZgłosićWyjątek();
      i++;
      z.możeZgłosićWyjątek();
      i++;
      z.możeZgłosićWyjątek();
      i++;
    } catch (Exception e) {
      System.out.println("Wyjątek wystąpił w instrukcji "+ i);
      //jakiś kod obsługi
    }
    if (i == 6) System.out.println("Wyjątek nie wystąpił");
  }
}

Zadanie 5

Czy deklaracja wyjątków należy do sygnatury metody? Przygotuj przykład, który to rozstrzyga.

Rozwiązanie

Nie. Deklaracja wyjątków nie należy do sygnatury metody, tak samo jak wartość zwrotna.

class WyjA extends Exception {}
class WyjB extends Exception {}

public class Zad5 {
  //z poniższych metod może być odkomentowana tylko jedna!
  //void test() {}
  //void test() throws WyjA {}
  //void test() throws WyjB {}
  //void test() throws WyjA, WyjB {}
  //void test() throws Exception {}
}