Personal tools

PO Wyjątki c.d. - ćwiczenia

From Studia Informatyczne

<<< Powrót do przedmiotu Programowanie obiektowe

<<< Powrót do wykładu Wyjątki c.d.

Spis treści

Zadanie 1

Zmodyfikuj klasę ZwalnianieZasobów2, aby zwalnianie odbywało się w bloku 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;
        //if (i == 8) break;
        //...

      } 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 2

Podczas rezerwowania i zwalniania zasobów zazwyczaj też może wystąpić wyjątek. Użyj pokazanej poniżej klasy Zasób4 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ób4 {
  Zasób4(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ów4 {
  public static void main(String[] args) throws Exception {
    for (int i = 0; i < 10; i++) {
      Zasób4 z1 = new Zasób4(i);
      Zasób4 z2 = new Zasób4(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;
        //...

      } 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 3

Sprawdź, czy finally jest wykonywane pomimo wystąpienia wyjątku w bloku catch z tej samej instrukcji?

Rozwiązanie

Tak, pokazuje to poniższy przykład.

public class Zad3 {
  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");
    }
  }
}

Zadanie 4

Napisz klasę, której konstruktor zgłasza wyjątek. W metodzie main() utwórz egzemplarz tej klasy i obsłuż wyjątek.

Rozwiązanie

public class Zad44 {
  Zad4() throws Exception {
    throw new Exception();
  }
 
  public static void main(String[] args) {
    try {
      Zad4 z = new Zad4();
    } catch (Exception e) {
      System.out.println("złapany!");
    }
  } 
}

Zadanie 5

Sprawdź, czy konstruktor podklasy nie może obsłużyć wyjątków zgłaszanych przez konstruktor nadklasy. Napisz przykładowy kod pokazujący, że konstruktor nadklasy jest wykonywany wcześniej niż wskazuje na to umiejscowienie słowa super w konstruktorze podklasy.

Rozwiązanie (część 1)

class Nadklasa1 {
  Nadklasa1() throws Exception {}
  Nadklasa1(int i) throws Exception {}
}

class Podklasa1 extends Nadklasa {
  Podklasa1() throws Exception {
    //nie wskazujemy konstruktora nadklasy, więc będzie użyty bezparametrowy
    //nie ma co otaczać instrukcją try-catch
  }
 
  Podklasa1(int i) throws Exception {
    //pierwszą instrukcją jest try-catch,
    //więc kompilator uzna, że nie wskazujemy konstruktora nadklasy
    //i użyje bezparametrowego
    try {
      //tu nie może być odowołania do konstruktora nadklasy, bo to nie jest pierwsza instrukcja
      //super(i);
      throw new Exception();
    } catch (Exception e) {}
  }
}

Rozwiązanie (część 2)

class Nadklasa2 {
  int dajInt() {
    System.out.println("Nadklasa2.dajInt()");
    return 0;
  }
  int i = dajInt();
 
  {
    System.out.println("blok inicjalizacji w Nadklasa2");
  }
 
  Nadklasa2(int i) {
    System.out.println("konstruktor nadklasy");
  }
}

public class Podklasa2 extends Nadklasa2 {
  {
    System.out.println("blok inicjalizacji w Podklasa2");
  }

  int inneDajInt() {
    System.out.println("Podklasa2.inneDajInt()");
    return 0;
  }
  int i = inneDajInt();  
 
  Podklasa2() {
    //musimy wskazać konstruktor, bo nie ma bezparametrowego
    super(0);
    System.out.println("konstruktor podklasy");
  }

  public static void main(String[] args) {
    Podklasa2 p = new Podklasa2();
  }
}
Nadklasa2.dajInt()
blok inicjalizacji w Nadklasa2
konstruktor nadklasy
blok inicjalizacji w Podklasa2
Podklasa2.inneDajInt()
konstruktor podklasy

Zadanie 6

Zmodyfikuj definicje wyjątków w przykładzie z PerpetuumMobile tak, aby metoda jedź() mogła zgłaszać wyjątek ŁamiePrawaFizyki

Rozwiązanie

class BłądContinuum extends Exception {}
class ŁamiePrawaFizyki extends RuntimeException {}

abstract class Samochód {
  abstract void jedź() throws BrakPaliwa;
}

interface WehikułCzasu {
  void jedź() throws ŁamiePrawaFizyki;
  void przenieśSięWCzasie() throws BłądContinuum;
}

class PerpetuumMobile extends Samochód implements WehikułCzasu {
  public void jedź() throws ŁamiePrawaFizyki {} 
  public void przenieśSięWCzasie() throws BłądContinuum {} 
}