« poprzedni punkt  następny punkt »

5. Wielowariantowe wybory za pomocą instrukcji switch

Zamiast wielokrotnych if - else if w niektórych przypadkach można zastosować instrukcję wyboru wielowariantowego switch. Ma ona następującą ogólną postać


switch (wyr) blok_switch

gdzie:
  • wyrażenie wyr musi być typu char, byte, short, lub int
  • blok_switch ma szczególną postać. W jego wnętrzu (pomiędzy nawiasami klamrowymi) można używać etykiet o postaci:
    case wyr_stałe : ins
    oraz
    default : ins // UWAGA. Etykieta default może być tylko jedna

Wyrażenie w nawiasach switch jest wyliczane, a jego wartość porównywana z wartościami wyrażeń stałych (zawartych w częściach oznaczanych przez etykiety case). Sterowanie jest przekazywane do tej instrukcji, którą poprzedza etykieta case z wyrażeniem stałym równym co do wartości wyrażeniu w nawiasach switch.
Od tego miejsca wykonanie programu przebiega dalej sekwencyjnie (po to by nie wykonywały się inne instrukcje oznaczone przez inne etykiety case, następujące po wybranej w rezultacie porównania, trzeba zastosować instrukcję break lub return).
Jeśli nie znajdzie się żadna etykieta "pasująca" do wartości wyrażenie w nawiasach switch, to sterowanie jest przekazywane do części oznaczanej przez etykietę default, a jeśli jej nie ma, to - do instrukcji następującej w programie po switch.

Rozważmy przykład klasy, która udostępnia metodę makeOp wykonania operacji arytmetycznych na elementach swoich obiektów - dwóch liczbach rzeczywistych.

public class SimpleCalc {

  private double a;
  private double b;

  public SimpleCalc(double x, double y) {
    a = x;
    b = y;
  }

  public double makeOp(char op) {

    double r = 0;

    switch(op) {
       case '+' : r = a + b; break;
       case '-' : r = a - b; break;
       case '*' : r = a * b; break;
       case '/' : r = a / b; break;
       default  : System.out.println("Nieznany kod operacji");
    }

    return r;
  }

}

class SimplecalcTest {

  public static void main(String[] args) {

    SimpleCalc sc = new SimpleCalc(1.2, 3.7);
    System.out.println( sc.makeOp('+'));
    System.out.println( sc.makeOp('-'));
    System.out.println( sc.makeOp('*'));
    System.out.println( sc.makeOp('/'));

  }
}

W metodzie makeOp wartość zmiennej op (typu char) steruje obliczeniami (np. jeśli zawiera znak '+' to sterowanie jest przekazywane do miejsca oznaczonego etykietą case '+', wartość r jest wyliczana jako suma a i b, a instrukcja break pozwala opuścić dalsze instrukcje zawarte w bloku switch).

Warto szczególnie podkreślić, że etykiety case są tworzone przez wyrażenia stałe. Wyrażenie stałe to takie, którego wartość jest znana w fazie kompilacji i nie może być zmieniona w fazie wykonania programu. Będzie to np. literał (taki jak '+'. '*' czy 1), nazwa stałej (zadeklarowanej jako final), wyrażenie składające się z literałów i nazw stałych połączonych operatorami języka (np. LMAX + 3/LMIN, gdzie LMAX i LMIN - nazwy stałych). Wartość wyrażenia stałego musi być typu całkowitego i dać się przekształcić do typu wyrażenia w nawiasach switch.

Nie należy tez zapominać o umieszczeniu instrukcji we właściwym momencie przerywających sekwencje operacji zawartych w bloku swicth.
Np. poniższa sekwencja:

double a = 0.1;
switch(n) {
case 1 : a = a + 1;
case 2 : a = a + 2;
case 3 : a = a + 3;
}
System.out.prinln(a);

wypisze: 6.1 (dla n = 1), 5.1 (dla n = 2) i 3.1 (dla n = 3), zaś dla innych wartości n inicjalną wartość zmiennej a (0.1). Jeśli chcemy uzyskać 1.1 dla n =1, 2.1 dla n=2 i 3.1 dla n=3 to po każdym wyliczeniu a należy wstawić instrukcję break, przerywającą sekwencyjne wykonywanie instrukcji zawartych w bloku i przekazującą sterowanie do pierwszej instrukcji poza switch.

Etykiety case i default mogą występować w dowolnej kolejności, ale w ramach jednego switch nie może być dwóch takich samych etykiet (nie może być dwóch wyrażeń stałych, które dają w rezultacie tę samą wartość np. 3 i 1 + 2 lub dwóch etykiet default).

Co jednak, jeśli instrukcje switch są włożone ? Okazuje się, że etykiety case i default są kojarzone zawsze ze "swoim" switch, możemy więc pisać np. tak:

switch(i) {
    case 1 : switch(testNum(i)) {
        case 1 : System.out.println("same one"); break;
        case 2 : System.out.println("double one"); break;
        default: System.out.println("other one"); break;
        }
        break;
    case 2 : System.out.println("two"); break;
    default: System.out.println("other two"); break;
}

(jeśli funkcja testNum zwraca podwojona wartość swojego argumentu, to wprowadzenie 1 da na wyjściu napis "double one", zaś 2 - napis "two")

Zwykła instrukcja break przerywa wykonanie tego bloku switch, w którym jest umieszczona.

Etykieta w programie jest identyfikatorem z następującym znakiem :. Nie należy mylić ogólnego pojęcia etykiety ze specjalnym przypadkiem "etykiety" case

Jeśli natomiast w instrukcji break podamy etykietę, to sterowanie może być przekazane z bloku switch do instrukcji wskazywanej przez tę etykietę. W ten sposób za pomocą break możemy wychodzić z głęboko zagnieżdżonych bloków switch.


Uwaga: stosowanie etykiet w instrukcji break dla wychodzenia z zagnieżdżonych bloków dotyczy rózwnież instrukcji sterujących for, while i do_while. Stosowanie etykiet podlega pewnym ograniczeniom - zob. opis języka na stronie sun.java,com.


« poprzedni punkt  następny punkt »