OCA Java imtahan mövzuları

The switch statement | Compile-time Constant Values

The switch statement

*FIGURE 1. The structure of a switch statement

switch-statement-in-java

Switch ifadələr ancaq aşağıdakı tipdə ola bilər:

  • int və Integer
  • byte və Byte
  • short və Short
  • char və Character
  • String (java 7`dən bəri)
  • enum values

float, double, boolean və long tipləri və həmçinin onların wrapper classları (Float, Double, Boolean, Long) switch ifadələr tərəfindən dəstəklənmir.

Mahiyyət baxımından bir iş görməsə belə aşağıdakı nümunədə verilmiş sintaksis səhv deyildir və normal compile və run olunur:

public static void main(String[] args) {
    switch (1) {
        default: break;
    }
    switch (2) { }
}

 

Compile-time Constant Values

Hər bir case ifadəsinin dəyəri switch ifadəsinin dəyəri ilə eyni tipdə olan (əgər switch dəyişəni String tipindədirsə, case ifadəsinin də dəyəri String tipində olmalıdır və ya switch ifadə char tipindədirsə case dəyərlər 65535-dən yuxarı ola bilməz) compile-time constant dəyərlər olmalıdır. Bunlar ola bilər:

  • literals;
  • enum constants;
  • final constant variables (final modifier ilə təyin olunmalı və elan olunduğu sətirdə literal dəyər mənimsədilməlidir; primitiv və String tiplər ola bilər, Wrapper classlar constant hesab edilmir).

Sonuncu bəndə əsasən wrapper classlar (Integer, Byte, Short, Character) switch ifadədə işlədilə bilər, amma case label kimi işlədilə bilməz. Suallarda buna diqqət etmək lazımdır.

Qısaca compile-time constant olması üçün dəyişən aşağıdakı şərtləri ödəməlidir:

  • final olmalıdır;
  • primitiv və ya String tipində olmalıdır;
  • elan olunduğu sətirdə dəyər mənimsədilmiş olmalıdır;
  • be assigned to a compile time constant expression.

Misal üçün private final int x = getX(); ifadəsində x də həmçinin compile-time constant hesab edilmir. Başqa bir nümunəyə baxaq:

private int getSortOrder(String firstName, final String lastName) {
    String middleName = "MBM";
    final String suffix = "MM";
    int id = 0;

    switch(firstName) {
        case "Test":             // String literal
            return 52;
        case suffix:             // final constant variable
            id = 7;
            break;
        case middleName:         // does not compile, because it is not final
            id = 5;
            break;
        case lastName:           // does not compile, final but not constant
            id = 8;
            break;
        case 5:                  // does not compile, not String
            id = 5;
            break;
        case 'J':                // does not compile, not String
            id = 10;
            break;
        case java.time.DayOfWeek.SUNDAY.toString(): //does not compile, enum
            id = 15;
            break;
        case "string".toUpperCase():  // does not compile
            break;
        case "string".toString():     // does not compile
            break;
        case "string".trim():         // does not compile
            break;
    }
   return id;
}

Bir sıra incə məqamlara da nəzər salaq. Misal üçün aşağıdakı nümunə compile xətası verəcək, çünki char birbaşa Integer tipində olan dəyişənə mənimsədilə bilməz:

Integer x = 1;  // int x = 1; is valid.
switch (x) {
    case 'a':   // does not compile
        System.out.println("a");
}

Bildiyimiz kimi char dəyişəninə rəqəm (numeric) tipli dəyər mənimsədə bilərik. Bu məntiqlə yanaşsaq deyə bilərik ki, switch char tipindədirsə case byte tipində ola bilər. Amma bu hər zaman doğru deyildir, çünki byte mənfi ədədlər də ala bilər, char isə mənfi dəyər qəbul edə bilməz:

char c = 'a';
switch (c) {
    case -1: System.out.println("-1"); // Doesn’t compile: "possible loss of precision"
}

Əgər case ifadədə -1 əvəzinə (char) -1  yazsaq compile olunacaq.

Həmçinin də switch ifadə əgər byte tipindədirsə, case dəyərlər -128 < case_label < 127 aralığında dəyər ala bilərlər.

byte b = 100;
switch (b) {
    case 100:
    case 'a': default: case 'b':
    case 150:  // does not compile
    case 200:  // does not compile
}

İmtahan üçün char dəyərlərin rəqəm qarşılığını bilmək tələb olunmur, amma ümumi olaraq yadda saxlaya bilərsiniz ki, ingilis əlifbasının bütün böyük və kiçik hərflərinin və eləcə də 0-9 aralığındakı rəqəmlərin hamısının rəqəm qarşılığı 127-dən kiçikdir. Yəni əgər switch ifadə byte tipindədirsə, case label olaraq qeyd etdiyimiz char dəyərlərin hər birini rahatlıqla istifadə edə bilərsiniz. ASCII kod siyahısına aşağıdakı linkdən baxa bilərsiniz:

http://www.asciitable.com/

Case dəyərlər təkrarlana bilməz, əks halda təkrarlanan sətir xəta verəcək:

switch (new Integer(2)) {
    case 1: System.out.println("1");
    case 2: System.out.println("2");
    case 3: System.out.println("3");
    case 2: System.out.println("duplicate 2");    // does not compile
    case 1: System.out.println("duplicate 1");    // does not compile
}

Nümunə bir az qarışıq formada da verilə bilər:

switch (0) {
    case 97: System.out.println("97");
    case 16: System.out.println("2");
    case (int)'b': System.out.println("98");
    case (int)'a': System.out.println("duplicate 97");  // does not compile
    case 8*2: System.out.println("duplicate 16");       // does not compile
}

Yaxşı olar ki, təsəvvürünüzə gələn bütün mümkün variantları yazıb özünüz üçün test edəsiniz.

Bir switch blokunda default ifadəsi ancaq bir dəfə istifadə oluna bilər, əks halda kod xəta verəcək. default ifadəsi switch`də istənilən yerdə yazıla bilər; əvvəldə, ortada, axırda, case ifadələri ilə yerləşmə ardıcıllığında heç bir məhdudiyyət yoxdur. Amma icra olunma ardıcıllığı fərqlidir, default əvvəldə və ya ortada yerləşməsindən asılı olmayaraq həmişə sonda icra olunur. Əvvəlcə case ifadələri bir-bir yoxlanılır və əgər heç bir uyğunluq olmasa o zaman default ifadəsi axtarılır və əgər varsa o zaman default icra olunur. Və ən vacib məqamlardan biri: əgər uyğunluq hansı sətirdə tapılsa, həmin sətirdən başlayaraq switch ifadəsinin sonuna kimi break ifadəsi olmazsa bütün case və default ifadələrinə daxil olur.

int dayOfWeek = 5;
switch(dayOfWeek) {
    case 0:
        System.out.print(" Sunday");
    default:
        System.out.print(" Weekday");
    case 6:
        System.out.println(" Saturday");
}

// Output: Weekday Saturday

 

Başqa bir maraqlı nümunəyə baxaq:

public void getTypeOfDayWithSwitchStatement(String dayOfWeekArg) {
    String typeOfDay;
    switch (dayOfWeekArg) {
        case "Monday":
            typeOfDay = "Start of work week";
            break;
        case "Tuesday":
        case "Wednesday":
        case "Thursday":
            typeOfDay = "Midweek";
            break;
        case "Friday":
            typeOfDay = "End of work week";
            break;
        case "Saturday":
        case "Sunday":
            typeOfDay = "Weekend";
            break;
        default:
            throw new IllegalArgumentException("Invalid day of the week");
    }

    System.out.println(typeOfDay);  // line A
}

Əgər bu metodda istənilən case ifadəsinin birinde typeOfDay dəyişəninə dəyər mənimsədilməsini və ya default`da throw ifadəsini commentə atsaq line A compile olunmayacaq. Çünki compiler yüz faiz əmin olmalıdır ki, istənilən hər bir situasiyada typeOfDay dəyişəninə dəyər mənimsədiləcək, əks halda local dəyişən olduğu üçün onu çap edə bilməz.

Switch ifadələrə göndərilən String obyektlərin case labela uyğun olub olmadığını yoxlamaq üçün Java equals() metodundan istifadə edir. Ümumiyyətlə, əgər müqayisə ediləcək şərtlərin sayı çoxdursa, o zaman if-then-else ifadəsi ilə müqayisədə switch ifadəsinin istifadə edilməsi daha məqsədəuyğundur. Çünki switch ifadəsi həm if-then-else ifadəsinə nisbətən daha oxunaqlıdı, həm də performans baxımından daha yaxşıdır. Çünki dərləmə (compilation) zamanı switch üçün “jump table” yaradılır və artıq icra (execution) zamanı hansı case label`ın uyğun gəldiyi yoxlanılmır, sadəcə hansı case`in icra olunacağına qərar verilir. Əlavə məlumat üçün aşağıdakı linkə baxa bilərsiniz:

https://goo.gl/iFjldb

Bəzən switch sintaksislərində “case else” label`ına rast gələ bilərsiniz. Switch ifadələrində bu cür sintaksis mövcud deyil, if`dəki else ilə bunu çaşdırmayın. “case else” əvəzinə “default” label istifadə olunur.

Switch ifadələrində enum da istifadə etmək mümkündür. Baxmayaraq ki, enum OCP imtahanı mövzularına daxildir, hər ehtimala qarşı tanış olmaqda fayda var. Təsəvvür üçün bir nümunəyə baxaq:

class TestEnumWithSwitch {
    public static void main(String[] args) {
        int i = 1;
        switch (Seasons.SUMMER) {
            default:     i++;
            case WINTER: i+=1;
            case SPRING: i+=2;
            case SUMMER: i+=3;
            case AUTUMN: i+=4;
        }
        System.out.println(i);  // output: 8
    }
}

enum Seasons { WINTER, SPRING, SUMMER, AUTUMN }

Bəzi suallarda maksimum diqqətli olmaq lazımdır, “sağı göstərib sol ilə də vura bilərlər”. Ani bir diqqətsizlik üzündən çox sadə bir sualı səhv də cavablandıra bilərsiniz. Aşağıdakı nümunəyə baxaq:

int i = 8 / 3 - 1;
switch(i){
    case: 0 System.out.print("0"); break;
    case: 1 System.out.print("1"); break;
    default: System.out.println("default");
}

Bu testdə ilkin olaraq diqqət 4-cü sətirə yönəldilir. switch ifadə double tipində dəyər qəbul edə bilməz, adətən bu prizmadan yanaşıb qərar qəbul edirik:

  • ya 4-cü sətir compile olunmur;
  • yaxud da 4-cü sətir compile olunur və i`nin dəyərinə əsasən hansı case label çap olunur onu təyin edirik.

Əslində isə səhv tamam başqa yerdədir: 6 və 7-ci sətirlərdə. case label`larda sintaksisə görə iki nöqtə case`in dəyərindən sonra yazılır, case`dən sonra yox. Bu səbəbdən kod compile olunmur.

Son olaraq switch ilə bağlı “Java sertifikat sualları” facebook qrupumuzda müzakirə edilmiş daha bir maraqlı sualı qeyd edirəm, cavabını özünüz təxmin etməyə çalışın:

class SwitchExample {
    public static void main(String[] args) {
        String str = null;
        switch (str) {
            case "null":
                System.out.println("1");
                break;
            case "":
                System.out.println("2");
                break;
            default:
                System.out.println("3");
        }
    }
}

Əgər təxminləriniz olmazsa, doğru cavab və izahı görmək üçün aşağıdakı linkə daxil ola bilərsiniz:

https://www.facebook.com/groups/javacertification/permalink/917643694951436/

 

[topics lang=az]

 

 “OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z0-808”, by J.Boyarsky & S.Selikoff

About the author

Mushfiq Mammadov

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.