Zagadka Java #7

Zagadki Java zawierają różnego rodzaju niuanse języka i „podchwytliwe” fragmenty kodu. Każda następna zagadka będzie zawierała odpowiedź i wyjaśnienie do poprzedniej. Lista wszystkich zagadek.

Jeżeli znasz odpowiedź, podziel się nią w komentarzu!

Zagadka Java #7

Czy poniższa klasa się skompiluje? Jeżeli tak, to jaki będzie efekt jej uruchomienia?

public class CatchThrowable {
  public static void main(String[] args) {
    try {
      System.out.println(divide(5, 0));
    } catch (Throwable t) {
      System.out.println("Wystąpił błąd. Czyżbyś dzielił przez zero?");
    }

    try {
      System.out.println(divide(5.0, 0.0));
    } catch (Throwable t) {
      System.out.println("Wystąpił błąd. Czyżbyś dzielił przez zero?");
    }
  }

  public static int divide(int x, int y) {
    return x / y;
  }

  public static double divide(double x, double y) {
    return x / y;
  }
}

Odpowiedź do poprzedniej zagadki #6

Poniżej znajdziesz odpowiedź do poprzedniej zagadki.

Przejdźmy po kolei przez instrukcje zawarte w klasie SpotTheError.

long longVal = 9876543210; // błąd kompilacji

Ta linia spowoduje błąd kompilacji. Liczby całkowite, które wpisujemy w kodzie naszych programów, są domyślnie typu int. Wartość 9876543210, którą próbujemy przypisać do zmiennej longVal, nie jest prawidłową liczbą typu int – wychodzi ona poza zakres. Największa liczba, jaką możemy reprezentować za pomocą typu int, to 2147483647. Aby przypisać większą liczbę do zmiennej typu long, należy na końcu liczby dodać literę L (L jak long). Poniższa linia byłaby prawidłowa i nie powodowałaby błędu kompilacji (zwróć uwagę na dodaną literę L na końcu liczby):

long longVal = 9876543210L; // ok

int intVal1 = 1_0; // ok

Ta linia jest poprawna. W języku Java możemy korzystać z znaku _ (podkreślenie), aby oddzielać od siebie cyfry w liczbach. Do zmiennej intVal1 zostanie przypisana liczba 10.


int intVal2 = 0xff; // ok

Ta linia także jest poprawna. Liczby zaczynające się od 0x (zero x) to liczby zapisane w systemie szesnastkowym. Do zmiennej intVal2 zostanie przypisana wartość 255.


String $fiveDollars = "$5"; // ok

W języku Java, nazwy zmiennych mogą zaczynać się od znaku dolara, więc powyższa linia jest poprawna.


String #ofPuzzlesSoFar = 6; // błąd kompilacji

Ta linia spowoduje błąd kompilacji. Nazwy w języku Java nie mogą zawierać znaku #.


float floatVal1 = 0; // ok

Ta linia jest poprawna – do zmiennej typu float przypisuje wartość typu int (ponieważ liczby całkowite są domyślnie typu int w języku Java). Typ float ma większy zakres niż typ int, tzn. może przechowywać więcej wartości, więc powyższe przypisanie jest poprawne.


float floatVal2 = 0.0; // błąd kompilacji

Ta linia spowoduje błąd kompilacji. Liczby rzeczywiste (z częścią ułamkową) w języku Java są domyślnie typu double. Ten typ ma szerszy zakres, niż typ float, więc kompilator zaprotestuje. Aby wskazać, że liczba a być traktowana jako liczba typu float, należy dodać na końcu liczby literę f (f od float). Poniższa linia nie powoduje błędu kompilacji:

float floatVal2 = 0.0f; // ok

byte byteVal1 = 1; // ok

Być może zaskakująco, ta linijka nie spowoduje błędu kompilacji – do zmiennej byteVal1 zostanie przypisana wartość 1. Jak już wspominałem, wartości całkowite w kodzie programów są domyślnie typu int, a typ byte ma mniejszy zakres, niż typ int. Dlaczego więc ta linijka kompiluje się bez błędów? W tym przypadku, kompilator dla naszej wygody automatycznie rzutuje wartość przypisywaną do zmiennej byteVal1 z int na byte. Dzieje się tak dlatego, że kompilator wie, że w tym przypadku przypisywana wartość nie wychodzi poza zakres typu byte, który może przechowywać wartości z zakresu od -128 do 127. Z kolei poniższa linia spowodowałaby błąd, ponieważ wartość 1000 wychodzi poza zakres typu byte – kompilator by zaprotestował:

byte byteVal1 = 1000; // błąd kompilacji

byte byteVal2 = (byte) -129; // ok

Gdyby nie rzutowanie, to powyższa linia powodowałaby błąd kompilacji. Do zmiennej byteVal2 przypisana zostanie wartość 127. Skąd taka wartość? W tym przypadku dojdzie do tzw. „przekręcenia licznika”. Wartość -129 jest o jeden mniejsza, niż minimalna liczba, którą mogą przechowywać zmienne typu byte. Następną liczbą jest 127 – jest to największa liczba dodatnia, którą można przypisać do zmiennej typu byte.


long anotherLong = 1;

switch (anotherLong) { // błąd kompilacji
  case 0:
    System.out.println("0");
    break;
  default:
    System.out.println(anotherLong);
    break;
}

Ten fragment kodu powoduje błąd kompilacji – instrukcja switch nie obsługuje wartości typu long.


W tej zagadce była jeszcze jedna, podchwytliwa linia kodu – spójrz na sygnaturę metody main:

public static final void main(String[] args) {

Do sygnatury metody main dodałem słowo kluczowe final. Nie powoduje to błędu kompilacji, a program działa poprawnie (o ile zakomentowane zostaną te instrukcje z ciała metody main, które powodują błąd kompilacji).

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Nie musisz podawać swojego imienia, e-mailu, ani strony www, aby opublikować komentarz. Komentarze muszą zostać zatwierdzone, aby były widoczne na stronie.