Java anahtarları içinde değişkenleri bildirme ve başlatma


100

Java anahtarları hakkında çılgın bir sorum var.

int key = 2;

switch (key) {
    case 1:
        int value = 1;
        break;
    case 2:
        value = 2;
        System.out.println(value);
        break;
    default:
        break;
}

Senaryo 1 - keyİki olduğunda, değeri başarılı bir şekilde
2 olarak yazdırır. Senaryo 2 - Yorum value = 2yapacağım case 2:zaman, yerel değişken değeri başlatılmamış olabilir diye ciyaklıyor .

Sorular:

Senaryo 1: Yürütme akışı case 1:(ne zaman key = 2) 'a gitmezse, değer değişkeninin türünü nasıl bilir int?

Senaryo 2: Derleyici değer değişkeninin türünü olarak biliyorsa, intiçindeki int value = 1;ifadeye erişmiş olmalıdır case 1:. (Beyan ve Başlatma). O zaman neden ben yorum yapmak için gidiyorum zaman sqawrk yapar value = 2içinde case 2:söyleyerek başlatıldı olmayabilir yerel değişken değerini .


13
Bu çılgınca bir soru değil, çok güzel bir soru.
biziclop


@PhilippeCarriere Aslında, bunun tersi olması gerektiğini düşünüyorum - buradaki cevap daha iyi (gönderi daha yeni olsa bile) çünkü JLS'ye doğrudan bir referans var ve bu yazıda farklı cevaplarda kapsanan sorunu iyi bir şekilde özetliyor. Ayrıca bakınız .
Tunaki

@Tunaki Bir kopya için açıklama "Bu soru daha önce sorulmuştu" ile başlar. Okuyorum, sonrakinin öncekinin kopyası olarak işaretlenmesi gerektiğini okuyorum. Ama bunun güzel unsurları olduğuna katılıyorum. Belki bir şekilde birleştirilmeleri gerekir?
Philippe Carriere

Ayrıca SO ile ilgili pek çok soru benim orijinal sorumun kopyası olarak işaretlendi, bu yüzden bunu yeni orijinal olarak işaretlemenin daha iyi olduğuna karar verirseniz, lütfen benim yerine buna başvurmak için tüm bağlantıları düzeltin.
Philippe Carriere

Yanıtlar:


115

Switch ifadeleri temelde kapsam açısından tuhaftır. Gönderen JLS bölüm 6.3 :

Bir bloktaki yerel değişken bildiriminin kapsamı (§14.4), bildirimin göründüğü bloğun geri kalanıdır, kendi başlatıcısı ile başlar ve yerel değişken bildirim bildiriminde sağdaki diğer bildiricileri içerir.

Senin durumunda, case 2aynı olduğu bloğun olarak case 1ve o halde sonra görüntülenen case 1yerel değişken dar olduğundan hazır yani ... yürütmek asla yazma size rağmen mantıksal asla deklarasyonu "yürütme". (Bir bildirim, başlatma olmasına rağmen gerçekten "yürütülebilir" değildir.)

value = 2;Atama hakkında yorum yaparsanız , derleyici hala hangi değişkenden bahsettiğinizi bilir, ancak ona bir değer atayan herhangi bir yürütme yolundan geçmemiş olursunuz, bu nedenle denediğinizde yapacağınız gibi bir hata alırsınız. kesinlikle atanmamış diğer yerel değişkenleri okuyun.

Ben şiddetle tavsiye ediyorum değil diğer durumlarda beyan yerel değişkenler kullanmak için - bu gördüğünüz gibi son derece kod kafa karıştırıcı yol açar. Yerel değişkenleri switch ifadelerine eklediğimde (nadiren yapmaya çalıştığım - ideal olarak vakalar çok kısa olmalı) genellikle yeni bir kapsam eklemeyi tercih ederim:

case 1: {
    int value = 1;
    ...
    break;
}
case 2: {
    int value = 2;
    ...
    break;
}

Bunun daha açık olduğuna inanıyorum.


11
"Bir bildirim için +1, başlatma olmasına rağmen gerçekten" çalıştırılabilir "değildir." Ve tavsiyeler için de teşekkürler Skeet.
namalfernandolk

1
Entegre JEP-325 ile, yerel değişkenlerin kapsamının resmi değişti ve anahtar blokları yerine vakalarda aynı isim kullanılabilir. Yine de benzer blok kodlamaya dayanır. Ayrıca, anahtar durumu başına bir değişkene atanan değer, anahtar ifadeleri ile çok daha uygun olacaktır.
Naman

Kaşlı ayraçlı yeni bir kapsam ekleme noktaları. Bunu yapabileceğini bile bilmiyordum.
Floating Sunfish

21

Değişken bildirildi (int olarak), ancak başlatılmadı (bir başlangıç ​​değeri atandı). Şu satırı düşünün:

int value = 1;

Gibi:

int value;
value = 1;

Bu int valuekısım derleyiciye, derleme zamanında değer adında bir değişkene sahip olduğunuzu söyler. value = 1Bölüm bunu başlatır, ama bu çalışma zamanında olur ve anahtar o dalı girilmezse hiç olmaz.


Derleme zamanı ve çalışma zamanında bildirim ve başlatmanın güzel açıklaması için +1.
namalfernandolk


3

JDK-12 erken erişim yapılarında JEP 325: Anahtar İfadeleri (Önizleme) entegrasyonu ile . Jon'un cevabından görülebilecek bazı değişiklikler var -

  1. Yerel Değişken Kapsamı - Anahtar durumlarındaki yerel değişkenler, artık tüm anahtar bloğu yerine vakanın kendisi için yerel olabilir. DahaDayfazla açıklama için enum sınıfınıdikkate alan bir örnek (Jon'un sözdizimsel olarak da denediğine benzer):

    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    // some another method implementation
    Day day = Day.valueOf(scanner.next());
    switch (day) {
        case MONDAY,TUESDAY -> {
            var temp = "mon-tue";
            System.out.println(temp);
        }
        case WEDNESDAY,THURSDAY -> {
            var temp = Date.from(Instant.now()); // same variable name 'temp'
            System.out.println(temp);
        }
        default ->{
            var temp = 0.04; // different types as well (not mandatory ofcourse)
            System.out.println(temp);
        }
    }
    
  2. İfadeleri Değiştir - Amaç bir değişkene bir değer atamak ve sonra onu kullanmaksa, bir kez anahtar ifadelerinden yararlanabilirsiniz. Örneğin

    private static void useSwitchExpression() {
        int key = 2;
        int value = switch (key) {
            case 1 ->  1;
            case 2 -> 2;
            default -> {break 0;}
        };
        System.out.println("value = " + value); // prints 'value = 2'
    }
    

0

Bu Açıklama yardımcı olabilir.

    int id=1;

    switch(id){
        default: 
            boolean b= false; // all switch scope going down, because there is no scope tag

        case 1:
            b = false;
        case 2:{
            //String b= "test"; you can't declare scope here. because it's in the scope @top
            b=true; // b is still accessible
        }
        case 3:{
            boolean c= true; // case c scope only
            b=true; // case 3 scope is whole switch
        }
        case 4:{
            boolean c= false; // case 4 scope only
        }
    }

0

Java özelliği:

https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.11

Bir etiketin kopması nedeniyle aniden tamamlanma durumu, etiketli ifadeler için genel kural tarafından ele alınır (§14.7).

https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.7

Etiketli ifadeler:

LabeledStatement: Tanımlayıcı: İfade

LabeledStatementNoShortIf: Identifier: StatementNoShortIf

C ve C ++ 'dan farklı olarak, Java programlama dilinin goto ifadesi yoktur; tanımlayıcı ifade etiketleri, etiketli ifadenin herhangi bir yerinde görünen break (§14.15) veya devam (§14.16) ifadeleriyle kullanılır.

Etiketli bir ifadenin etiketinin kapsamı, hemen içerilen Bildirimdir.

Başka bir deyişle, durum 1, durum 2, anahtar deyimi içindeki etiketlerdir. break ve continue ifadeleri etiketlere uygulanabilir.

Etiketler ifadenin kapsamını paylaştığından, etiketler içinde tanımlanan tüm değişkenler switch ifadesinin kapsamını paylaşır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.