10 lipca 2008

SCJP - Instrukcje warunkowe

Zacząłem ostatnio nowy projekt, połączony ze zwiedzaniem nowego miasta, więc czasu na SCJP zostało niewiele, ale dzisiaj akurat pada, więc siadam do komputera i tym samym zaczynam przerabiać piąty rozdział Książki. Będzie o instrukcjach warunkowych ‘if’ i ‘switch’.

Instrukcja warunkowa ‘if’ nie należy do szczególnie zagadkowych. Czytając Książkę natrafiłem właściwie tylko na jedną rzecz wartą powtórzenia – zerknijmy na poniższy przykład.

public static void main(String[] args) {
if (1 == 2)
if (2 == 3)
System.out.println("1 == 2 & 2 == 3");
else
System.out.println("1 != 2");
}

Na pierwszy rzut oka wygląda na to, że uruchomienie programu spowoduje wyświetlenie napisu "1 != 2", ale jest inaczej. Niezależnie od tego, jakie wcięcia zrobimy w naszym kodzie, ‘else’ dotyczy drugiej, zagnieżdżonej instrukcji ‘if’. Prawidłowo sformatowany kod wygląda tak

public static void main(String[] args) {
if (1 == 2)
if (2 == 3)
System.out.println("1 == 2 & 2 == 3");
else
System.out.println("1 != 2");
}

Możemy tłumaczyć się przed samymi sobą, że wiedzielibyśmy, jak wykona się powyższy program, gdyby nie moje wprowadzające w błąd wcięcia, ale to jest właśnie to, na co musimy się uczulić przed egzaminem na SCJP – na to, że będziemy celowo wprowadzani w błąd. W każdym razie, obowiązuje następująca zasada – ‘else’ należy do najbardziej zagnieżdżonej instrukcji ‘if’, do jakiej może należeć.

Instrukcja ‘switch’ jest z jednej strony dobrze znana, ale z drugiej, raczej rzadko stosowana, więc kilka słów przypomnienia może się przydać. Zacznijmy od poniższego przykładu.
 
public static void main(String[] args) {
int x = 5;

switch (x) {
case 1:
System.out.println("jeden");
break;
default:
System.out.println("jakaś inna cyfra");
case 2:
System.out.println("dwa");
break;
case 3:
case 4:
System.out.println("co najmniej trzy");
}
}

Efektem uruchomienia tego programu jest

jakaś inna cyfra
dwa

Zapamiętajmy kilka faktów, jak ten, że wariant domyślny (tj. etykieta ‘default’) nie musi być umieszczony jako ostatni, na końcu instrukcji ‘switch’. Pamiętajmy także, że wariant, który zostanie wybrany w trakcje wykonania jest tylko punktem początkowym, punktem wejścia. Kod będzie wykonywany aż do napotkania instrukcji ‘break’. Instrukcja ‘switch’ jest w pewnym sensie podobna do instrukcji ‘goto’ – jest to skok do pewnej etykiety, w zależności od wartości testowanej zmiennej.

Instrukcja ‘switch’ może operować na zmiennych i wartościach typu char, byte, short lub int oraz na typach wyliczeniowych (‘enum’). Argumenty dla poszczególnych wariantów (tj. dla etykiet ‘case’) muszą także być odpowiedniego typu, tj. dla typów numerycznych muszą mieścić się w odpowiednim zakresie. Przykładowo, kod

public static void main(String[] args) {
byte x = 4;

switch (x) {
case 127:
System.out.println("sto dwadzieścia siedem");
break;
case 128: // błąd
System.out.println("sto dwadzieścia osiem");
break;
}
}

się nie skompiluje, jako że zmienna ‘x’ jest typu ‘byte’, który przyjmuje wartości z zakresu od -128 do 127. Argumenty dla wariantów muszą być wartościami znanymi w czasie kompilacji, a więc poza literałami, mogą to być tylko zmienne finalne, z wartością przypisaną w czasie deklaracji. Przykładowo, kod

public static void main(String[] args) {
final byte a = 64;
final byte b;
b = 32;

byte x = 127;
switch (x) {
case a:
case b: // błąd
System.out.println("potęgi dwójki");
}
}

się nie skompiluje, jako że zmienna ‘b’ nie jest zainicjalizowana w czasie deklaracji, a została użyta jako argument wariantu.

1 komentarz:

Mariusz Lipiński pisze...

Uwaga, zmienna x zadeklarowana tak:

final static int x = 1;

jest uważana za stałą i może być użyta jako wartość etykiety case, ale już zadeklarowana tak:

final static Integer x = 1;

nie! Typ musi być typem prymitywnym.