Her durumda bir değer aralığına sahip switch deyimi mi kullanıyorsunuz?


94

Java'da, her vakanın birden fazla değer içerdiği bir switch ifadesi yazmak mümkün müdür? Örneğin (açıkça aşağıdaki kod çalışmayacaktır):

switch (num) {
    case 1 .. 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6 .. 10:
        System.out.println("testing case 6 to 10");
        break;
}

Sanırım bu Objective C'de yapılabilir, Java'da benzer bir şey var mı? Ya da sadece kullanmalısınız if, else ifbunun yerine ifadeleri?


Düz C'de bile buna izin veren uzantılar var.
arshajii

Bu durumda belki if/elsedaha iyi bir çözüm olabilir.
Eric Wang

Bugün değil, ama Java halkı bunun için seçenekleri, anahtar ifadelerindeki Kalıp Eşleştirme ile birlikte araştırıyorlar (Scala'dan çokça ödünç alıyorum diyebilirim). Olası fikirleri yakalayan bu belgede "bekçi" kelimesini arayın: cr.openjdk.java.net/~briangoetz/amber/switch-rehab.html
Luke Usherwood

Yanıtlar:


101

Java'da böyle bir şey yok. Neden aşağıdakileri yapmıyorsunuz?

public static boolean isBetween(int x, int lower, int upper) {
  return lower <= x && x <= upper;
}

if (isBetween(num, 1, 5)) {
  System.out.println("testing case 1 to 5");
} else if (isBetween(num, 6, 10)) {
  System.out.println("testing case 6 to 10");
}

1
Bu harika çalışıyor ve basit. Ayrıca, aralıkta olmayan sayıları seçmek istiyorsanız tek ihtiyacınız olan şudur: (! İsBet Between ..., good job.
a54studio

1
@missingfaktor Cevabınızı biraz eleştirdim . Yani, muhtemelen bir şeye cevap vermek istersiniz. +1 olsa da.
Alexander Malakhov

@MCEmperor, lütfen cevabımı kişisel biçimlendirme tercihlerinizle değiştirmeyin. Bu kullanışlı bir düzenleme değil.
missingfaktor

@missingfaktor Üzgünüm. Ancak bu düzenleme uzun zaman önce onaylandı; Bunu yaptığımı bile hatırlamıyordum.
MC Emperor

1
Karşılaştığım switchçoğu dilde ifadelerin neredeyse işe yaramaz görünmesi garip, neden onları biraz daha geliştirmediklerinden emin değilim. Aralık gibi basit bir şey bile tuhaf bir şekilde mümkün değil.
Hasen

77

switchİfadelerle bu tür davranışlara en yakın şekilde

switch (num) {
case 1:
case 2:
case 3:
case 4:
case 5:
     System.out.println("1 through 5");
     break;
case 6:
case 7:
case 8:
case 9:
case 10:
     System.out.println("6 through 10");
     break;
}

ifİfadeleri kullanın .


Bunun tam olarak kaçınmaya çalıştığına neredeyse eminim.
Hasen

@Hasen, bu yüzden if ifadelerini kullanmanızı öneriyorum :)
Jeffrey

Öyleyse yukarıdaki Eric Wang gibi bir yorum daha iyi olurdu.
Hasen

30

diğer bir alternatif ise matematik işlemini bölerek kullanmaktır, örneğin:

switch ((int) num/10) {
    case 1:
        System.out.println("10-19");
        break;
    case 2:
        System.out.println("20-29");
        break;
    case 3:
        System.out.println("30-39");
        break;
    case 4:
        System.out.println("40-49");
        break;
    default:
        break;
}

Ancak, görebileceğiniz gibi, bu yalnızca aralık her durumda sabitlendiğinde kullanılabilir.


6
Bu, 100'e bölünmüş http durum kodlarıyla güzel bir şekilde çalışıyor.
Stefan

14

Bunu Java'da yapabileceğini sanmıyorum. En iyi bahis, kodu aralığın son durumuna koymaktır.

switch (num) {
  case 1: case 2: case 3: case 4: case 5: 
     System.Out.Println("testing case 1 to 5");
     break;
  case 6: case 7: case 8: case 9: case 10:
     System.Out.Println("testing case 6 to 10");
     break;
  default:
     //
}

11

Bu yazının eski olduğunu biliyorum ama bu cevabın biraz tanınmayı hak ettiğine inanıyorum. Switch ifadesinden kaçınmaya gerek yoktur. Bu, java'da yapılabilir, ancak durumlarda değil switch deyimiyle yapılabilir. Üçlü operatörlerin kullanılmasını içerir.

public class Solution {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = Integer.parseInt(sc.nextLine());

        switch ((1 <= num && num <= 5 ) ? 0 :
                (6 <= num && num <= 10) ? 1 : 2) {

            case 0:
                System.out.println("I'm between one and five inclusive.");
                break;
            case 1:
                System.out.println("I'm between 6 and 10 inclusive.");
                break;
            case 2:
                System.out.println("I'm not between one and five or 6 and 10 inclusive.");
                break;
        }
    }
}

1
Güzel çözüm! Java 7 ve üstü ile bir String'i de açabilirsiniz, böylece vakalarınız daha da kendi kendini belgelendirebilir, örneğin switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...ve sonra case "1 .. 5":.
Daniel Widdis

@DanielWiddis: Tutarlılığı sağlamak için dizeler yerine enum kullanmanızı öneririm.
nmatt

@nmatt Genel olarak katılıyorum. "1 .. 5" stili sözdiziminin kullanımına izin vermeye çalışıyordum.
Daniel Widdis

2
@DanielWiddis: Kesinlikle iyi bir şey; Enum sabitlerine FROM_1_TO_5 gibi bir isim verirdim. Genellikle aralıkların belirli bir anlamı vardır ve bu durumda enum sabitleri aralığın anlamına göre adlandırılabilir.
nmatt

1
Sanırım her iki seçeneğin de 0, 1 veya 2'den daha iyi olduğunu kabul edebiliriz.
Daniel Widdis

10
  case 1: case 2: case 3: case 4: case 5: 
         System.out.println("testing case 1 to 5");
         break;
  case 6: case 7: case 8: case 9: case 10:
         System.out.println("testing case 6 to 10");
         break;
  default:
         System.out.println("default"); 

6

Veya tekli vakalarınızı amaçlandığı gibi kullanabilir ve menzil talimatlarını aşağıdaki gibi belirtmek için varsayılan durumunuzu kullanabilirsiniz:

switch(n) {
    case 1 : System.out.println("case 1"); break;
    case 4 : System.out.println("case 4"); break;
    case 99 : System.out.println("case 99"); break;
    default :
        if (n >= 10 && n <= 15)
            System.out.println("10-15 range"); 
        else if (n >= 100 && n <= 200)
            System.out.println("100-200 range");
        else
            System.out.println("Your default case");
        break;   
}

Bu her zaman yaptığım şeydir, ancak aynı zamanda durumlar arasına bir yorum da eklerim, örneğin: // 10-15 varsayılan aşağıya bakın
Perdi Estaquel

5

Switch kullanmanız gerekiyorsa bunu deneyin.

public static int range(int num){ 
    if ( 10 < num && num < 20)
        return 1;
    if ( 20 <= num && num < 30)
        return 2;
    return 3;
}

public static final int TEN_TWENTY = 1;
public static final int TWENTY_THIRTY = 2;

public static void main(String[]args){
    int a = 110;
    switch (range(a)){
        case TEN_TWENTY: 
            System.out.println("10-20"); 
            break;
        case TWENTY_THIRTY: 
            System.out.println("20-30"); 
            break;
        default: break;
    }
}

sen de açıklama yapar mısın ..?
user1140237

İşlev aralığı, girdi argümanına göre bir değer döndürür, böylece "değer aralığı" saptaması burada anahtar durum cümlesi ile birlikte yapılabilir.
zl9394

Bu benim kullanım durumum için çalıştı, 2 int değişkenim var ve 2 değişkenin aynı aralıkta olup olmadığını kontrol etmek istiyorum (10-20), (20-30), .... böyle
Sameer Kazi

Magic int değerleri yerine bir enum kullanmanızı öneririm.
nmatt

4

Hayır bunu yapamazsın. Yapabileceğin en iyi şey bu

case 1:
case 2:
case 3:
case 4:
case 5: 
  System.Out.Println("testing case 1 to 5");
break;

4

İşte gitmenin güzel ve minimalist bir yolu

(num > 1 && num < 5) ? first_case_method() 
                     : System.out.println("testing case 1 to 5")
                     : (num > 5 && num < 7)  ? System.out.println("testing case 5 to 7") 
                     : (num > 7 && num < 8)  ? System.out.println("testing case 7 to 8") 
                     : (num > 8 && num < 9)  ? System.out.println("testing case 8 to 9") 
                     : ... 
                     : System.out.println("default");

Bunu açıklayabilir misin? - 'mini ifs'i alıyorum ama bu idk dışında.
Kamin Pallaghy

@Tunaki bu, if..elseifüçlü operatörü ( condition ? statementIfTrue : statementIfFalse) kademeli olarak kullanan bir alternatiftir .
Williem

3

Anahtar ifadeleri tarafından izin verilen düşüşcase mekanizmasını kullanarak aynı ifadede birkaç koşulu gruplamak mümkündür , bu Java eğitiminde belirtilmiştir ve §14.11 bölümünde tam olarak belirtilmiştir . Anahtar Bildirimi ait Java Dili Şartname .

Aşağıdaki kod parçacığı eğiticideki bir örnekten alınmıştır, her aydaki gün sayısını hesaplar (1. aydan 12. aya kadar numaralandırılmıştır):

switch (month) {
    case 1: case 3: case 5:
    case 7: case 8: case 10:
    case 12:
        numDays = 31;
        break;
    case 4: case 6:
    case 9: case 11:
        numDays = 30;
        break;
    case 2:
        if (((year % 4 == 0) && 
             !(year % 100 == 0))
             || (year % 400 == 0))
            numDays = 29;
        else
            numDays = 28;
        break;
    default:
        System.out.println("Invalid month.");
        break;
}

Gördüğünüz gibi, bir dizi değeri tek bir caseifadede kapsamak için tek alternatif, olası değerlerin her birini tek tek, birbiri ardına listelemektir. Ek bir örnek olarak, sözde kodun soruya nasıl uygulanacağı aşağıda açıklanmıştır:

switch(num) {
    case 1: case 2: case 3: case 4: case 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6: case 7: case 8: case 9: case 10:
        System.out.println("testing case 6 to 10");
        break;
}

3

enumAralıklarınızı temsil etmek için bir kullanabilirsiniz ,

public static enum IntRange {
  ONE_TO_FIVE, SIX_TO_TEN;
  public boolean isInRange(int v) {
    switch (this) {
    case ONE_TO_FIVE:
      return (v >= 1 && v <= 5);
    case SIX_TO_TEN:
      return (v >= 6 && v <= 10);
    }
    return false;
  }

  public static IntRange getValue(int v) {
    if (v >= 1 && v <= 5) {
      return ONE_TO_FIVE;
    } else if (v >= 6 && v <= 10) {
      return SIX_TO_TEN;
    }
    return null;
  }
}

3

NavigableMapGibi bir uygulama kullanın TreeMap.

/* Setup */
NavigableMap<Integer, Optional<String>> messages = new TreeMap<>();
messages.put(Integer.MIN_VALUE, Optional.empty());
messages.put(1, Optional.of("testing case 1 to 5"));
messages.put(6, Optional.of("testing case 6 to 10"));
messages.put(11, Optional.empty());

/* Use */
messages.floorEntry(3).getValue().ifPresent(System.out::println);

Mükemmel çözüm! if (messages.floorEntry(value)!=null) Bir Tamsayı değeri kullanıyorsanız kullanarak boş değeri kontrol etmeyi unutmayın
Ch Vas

1
@ChVas Haritanın burada ayarlanma şekli floorEntry()asla geri dönmeyecek null( Integer.MIN_VALUEanahtarın girilmesi bunu önlemek içindir). Ancak, değer türünüzden bağımsız olarak, geçerli aralığın dışındaki anahtarları nasıl kullanacağınıza karar vermeniz gerekir.
erickson

3

Java 12'den itibaren desteklenmektedir . JEP 354'e bakın . Burada "aralık" olasılığı yoktur, ancak yararlı da olabilir.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);//number of letters
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

Bunu ınts üzerinde de uygulayabilmelisiniz. defaultAnahtar ifadenizin kapsamlı olması gerektiğini unutmayın ( anahtar kelime kullanarak veya durum ifadelerinde olası tüm değerleri kullanarak).


2

@missingfaktor'ın cevabı gerçekten doğru ama biraz fazla karmaşık. Kod daha ayrıntılıdır (en azından sürekli aralıklar için), olabilir ve uzun, kayan nokta, Tamsayı vb. İçin aşırı yükler / yayınlar ve / veya parametrelendirme gerektirir.

if (num < 1)
    System.Out.Println("invalid case: " + num); // you should verify that anyway
else if (num <= 5)
    System.Out.Println("1 to 5");
else if (num <= 10)
    System.Out.Println("6 to 10");
else if (num <= 42)
    System.Out.Println("11 to 42");
else    
    System.Out.Println("43 to +infinity");

3
Geç yanıt için özür dilerim, son zamanlarda SO yanıtlarına yetişemiyorum. Eleştirinize tek tek cevap vereceğim. 1. Kod biraz daha ayrıntılıdır, evet ve ayrıca bazı gereksiz hesaplamalar da yapar. Ancak bu IMO, bu durumda açıklığa yardımcı oluyor. Kodunuzda, merdivenden düşerken önceki durumları hatırlamak gerekir.
missingfaktor

2
Aşırı yükleme ve yayın gerektirmeye gelince, bu geçerli bir eleştiri IMO değil. Java'nın sayısal türler üzerinde soyutlama yapmanın mantıklı bir yolu olmadığı, bu yaklaşımdan çok Java'nın sınırlamaları hakkında bilgi veriyor. NumBu noktayı daha iyi anlamak istiyorsanız Haskell'in tip sınıfını keşfetmek isteyebilirsiniz.
missingfaktor

@missingfaktor 1. Sanırım bu bir zevk meselesi. Sürekli aralıklarla uğraşırken, ben şahsen ifs'yi kademeli olarak alt aralıktan döküyormuşum gibi düşünmeyi seviyorum . Ayrıca, bir gereksiz hesaplama hiç bir sorun değildir, ancak gereksiz karşılaştırma biraz endişe verici: bazı düzenleme sonrasında senkron, örneğin dışında komşu karşılaştırmalar yapmak için daha basit olur: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). Neyse, o kadar da önemli değil.
Alexander Malakhov

2. Kabul edildi - Java'nın sınırlaması, ancak çalışmamız gereken şey bu ve orijinal kodunuz çeşitli türler için çoğaltılacak. Bu özel durumda , Haskell'in yaklaşımı daha iyi olmasına rağmen, bir problem Number sınıfı kullanılarak hafifletilebilir (Haskell'i gerçekten öğrenemedim, ancak C ++ 'nın "Kavramlar Işığı" na benziyor. Ayrıca, bunu kastettiğine inanıyorum Real, değil Num).
Alexander Malakhov

0

0..100 aralığındaki giriş sayısı için

int n1 = 75; // input value
String res; int n=0; 
int[] a ={0,20,35,55,70,85,101};

for(; n1>=a[n]; n++);
switch(6-n+1) {
  case 1: res="A"; break;
  case 2: res="B"; break;
  case 3: res="C"; break;
  case 4: res="D"; break;
  case 5: res="E"; break;
  default:res="F";
}
System.out.println(res);

0

Bu tür davranış Java'da desteklenmez. Ancak, buna ihtiyaç duyan büyük bir projeniz varsa, projenizde Groovy kodunda karıştırmayı düşünün. Groovy kod bayt kodu olarak derlenir ve JVM ile çalıştırılabilir. Çalıştığım şirket, hizmet sınıfları yazmak için Groovy'yi ve diğer her şeyi yazmak için Java'yı kullanıyor.

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.