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).