Derleyici neden anahtardaki her kod bloğundan sonra otomatik olarak break ifadeleri koymuyor? Tarihsel nedenlerle mi? Birden çok kod bloğunun ne zaman yürütülmesini istersiniz?
Yanıtlar:
Bazen aynı kod bloğuyla ilişkili birden fazla vakaya sahip olmak yararlıdır, örneğin
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
vb. Sadece bir örnek.
Tecrübelerime göre, genellikle "gözden düşmek" ve bir durum için birden fazla kod bloğunun çalıştırılması kötü bir tarzdır, ancak bazı durumlarda bunun için kullanımları olabilir.
// Intentional fallthrough.
arayı atladığınızda her zaman satırlara bir yorum ekleyin . Bana göre "kazara bir molayı unutmak kolay" kadar kötü bir tarz değil. Not: Tabii ki cevabın kendisinde olduğu gibi basit durumlarda değil.
case
bu şekilde bir araya getirilirse yorumla uğraşmam . Aralarında kod varsa evet, yorum muhtemelen haklı.
case
, örneğin:, case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
vakalar arasında ara vermeye gerek kalmadan. Pascal bunu yapabilir: "case deyimi, sıralı ifadenin değerini her bir seçici ile karşılaştırır; bu bir sabit, bir alt aralık veya virgülle ayrılmış bir liste olabilir." ( wiki.freepascal.org/Case )
Tarihsel olarak , bunun nedeni case
esasen bir çağrının hedef noktasılabel
olarak da bilinen a'yı tanımlamasıydı . Switch deyimi ve bununla ilişkili durumlar, bir kod akışına birden çok potansiyel giriş noktası olan çok yollu bir dalı temsil eder.goto
Tüm söylenenler, break
neredeyse her zaman her vakanın sonunda sahip olmayı tercih edeceğiniz varsayılan davranış olan neredeyse sonsuz sayıda not edilmiştir .
Java, C'den gelir ve bu C'den gelen sözdizimi.
Birden çok durum ifadesinin yalnızca bir yürütme yoluna sahip olmasını istediğiniz zamanlar vardır. Aşağıda, ayda kaç gün olduğunu size söyleyecek bir örnek var.
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
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;
}
System.out.println("Number of Days = " + numDays);
}
}
Bunun bir hata olduğunu düşünüyorum. Bir dil yapısı break
olarak, varsayılan olarak sahip olmak ve bunun yerine bir fallthrough
anahtar kelimeye sahip olmak kadar kolaydır . Yazdığım ve okuduğum kodların çoğu her durumdan sonra bir ara veriyor.
continue <case name>
Hangisinin hangi durum ifadesiyle devam edileceğini açıkça belirtmeye izin vermesini öneririm ;
case
Akım içinde keyfi bir duruma izin verirken switch
, bu sadece bir goto
. ;-)
Vakaların gözden geçirilmesi ile her türlü ilginç şeyi yapabilirsiniz.
Örneğin, tüm durumlar için belirli bir eylemi yapmak istediğinizi varsayalım, ancak belirli bir durumda bu eylemi artı başka bir şey yapmak istiyorsunuz. Fall-through ile bir switch deyimi kullanmak bunu oldukça kolaylaştıracaktır.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Elbette break
bir vaka sonunda ifadeyi unutmak ve beklenmedik davranışlara neden olmak kolaydır . İyi derleyiciler, break ifadesini atladığınızda sizi uyaracaktır.
Derleyici neden anahtardaki her kod bloğundan sonra otomatik olarak break ifadeleri koymuyor?
Kenara bırakırsak iyi arzusu (-özel kılıflı olabilir) çeşitli durumlar için aynı blok kullanmak mümkün ...
Tarihsel nedenlerle mi? Birden çok kod bloğunun ne zaman yürütülmesini istersiniz?
Esas olarak C ile uyumluluk içindir ve muhtemelen goto
anahtar kelimelerin dünyayı dolaştığı eski günlerden kalma eski bir hack . Bu does gibi tabii bazı şaşırtıcı şeyler etkinleştirmek, Duff Cihazı , ama bu olsun onun lehine bir nokta veya bir ... tartışmacı en iyi karşı.
break
Sonra anahtarı case
s anahtarı tablolara fallthrough önlemek için kullanılır. İlginç bir şekilde bu artık JEP-325 aracılığıyla uygulanan yeni oluşturulmuş anahtar etiketleri aracılığıyla gerçekleştirilebilir .
Bu değişikliklerle, daha da gösterildiği gibi break
her anahtardan case
kaçınılabilir: -
public class SwitchExpressionsNoFallThrough {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int value = scanner.nextInt();
/*
* Before JEP-325
*/
switch (value) {
case 1:
System.out.println("one");
case 2:
System.out.println("two");
default:
System.out.println("many");
}
/*
* After JEP-325
*/
switch (value) {
case 1 ->System.out.println("one");
case 2 ->System.out.println("two");
default ->System.out.println("many");
}
}
}
Açık JDK-12 ile birlikte yukarıda kod yürütme , Karşılaştırmalı çıkış olarak görülebilir
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
ve
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
ve tabii ki değişmeyen şey
// input
3
many // default case match
many // branches to 'default' as well
Dolayısıyla, aynı şeyi yapmak için birkaç duruma ihtiyacınız varsa kodu tekrarlamanız gerekmez:
case THIS:
case THAT:
{
code;
break;
}
Veya aşağıdaki gibi şeyler yapabilirsiniz:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
Basamaklı bir tarzda.
Bana sorarsan gerçekten hata / kafa karışıklığı eğilimli.
do this
ve do that
bunun için ama sadece do that
bunun için?
Tarihsel kayıtlara gelince, Tony Hoare 1960'larda "yapılandırılmış programlama" devrimi sırasında vaka açıklamasını icat etti. Tony'nin vaka ifadesi, vaka başına birden fazla etiketi ve kötü kokulu break
ifadeler olmadan otomatik çıkışı destekledi . Bir açıklık gerekliliği break
, BCPL / B / C hattından gelen bir şeydi. Dennis Ritchie yazıyor (ACM HOPL-II'de):
Örneğin, bir BCPL değiştirme ifadesinden kaçan son durum, 1960'larda öğrendiğimizde dilde mevcut değildi ve bu nedenle, break anahtar kelimesinin B ve C anahtar ifadesinden kaçmak için aşırı yüklenmesi bilinçli olmaktan ziyade farklı evrime borçludur. değişiklik.
BCPL hakkında herhangi bir tarihi yazı bulamadım, ancak Ritchie'nin yorumu, bunun break
aşağı yukarı tarihi bir kaza olduğunu gösteriyor. BCPL daha sonra sorunu çözdü, ancak belki de Ritchie ve Thompson Unix'i icat etmekle çok meşguldüler, böyle bir ayrıntıyla uğraşılmayacak :-)
break
"birden fazla kod bloğunun yürütülmesine" izin verdiğini biliyordu ve bu tasarım seçiminin motivasyonuyla daha çok ilgileniyor. Diğerleri C'den Java'ya kadar iyi bilinen mirastan bahsetti ve bu cevap araştırmayı C öncesi günlere daha da itti. Keşke en başından beri bu (çok ilkel olsa da) kalıp eşleşmesine sahip olsaydık.
Java, mirası Duff's Device olarak bilinen bir tekniği içeren C'den türetilmiştir . Bir break;
ifade olmadan kontrolün bir vakadan diğerine geçtiği gerçeğine dayanan bir optimizasyon . C standardize edildiğinde, "doğada" böyle bir çok kod vardı ve bu tür yapıları kırmak için dili değiştirmek ters etki yaratabilirdi.
İnsanların daha önce söylediği gibi, düşmeye izin vermek ve bu bir hata değil, bir özellik. Çok fazla break
ifade sizi rahatsız ediyorsa, return
bunun yerine ifadeler kullanarak bunlardan kolayca kurtulabilirsiniz . Bu aslında iyi bir uygulamadır, çünkü yöntemleriniz olabildiğince küçük olmalıdır (okunabilirlik ve sürdürülebilirlik açısından), bu nedenle bir switch
ifade zaten bir yöntem için yeterince büyüktür, bu nedenle iyi bir yöntem başka hiçbir şey içermemelidir, bu Bir örnek:
public class SwitchTester{
private static final Log log = LogFactory.getLog(SwitchTester.class);
public static void main(String[] args){
log.info(monthsOfTheSeason(Season.WINTER));
log.info(monthsOfTheSeason(Season.SPRING));
log.info(monthsOfTheSeason(Season.SUMMER));
log.info(monthsOfTheSeason(Season.AUTUMN));
}
enum Season{WINTER, SPRING, SUMMER, AUTUMN};
static String monthsOfTheSeason(Season season){
switch(season){
case WINTER:
return "Dec, Jan, Feb";
case SPRING:
return "Mar, Apr, May";
case SUMMER:
return "Jun, Jul, Aug";
case AUTUMN:
return "Sep, Oct, Nov";
default:
//actually a NullPointerException will be thrown before reaching this
throw new IllegalArgumentException("Season must not be null");
}
}
}
Yürütme yazdırır:
12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb
12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May
12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug
12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov
beklenildiği gibi.
Derleyici tarafından otomatik bir break eklenmemiş olması 1 <= a <= 3
, break ifadesini 1 ve 2'den kaldırmak gibi koşulları test etmek için bir anahtar / durum kullanmayı mümkün kılar .
switch(a) {
case 1: //I'm between 1 and 3
case 2: //I'm between 1 and 3
case 3: //I'm between 1 and 3
break;
}
Bu eski bir soru ama aslında bugün vakayı break cümlesi olmadan kullanmaya başladım. Break kullanmamak, farklı işlevleri sırayla birleştirmeniz gerektiğinde aslında çok kullanışlıdır.
örneğin kullanıcının kimliğini zaman belirteci ile doğrulamak için http yanıt kodlarını kullanma
sunucu yanıt kodu 401 - belirteç güncel değil -> belirteci yeniden oluşturun ve kullanıcının oturum açın.
sunucu yanıt kodu 200 - belirteç tamam -> kullanıcı oturum açın.
durumda ifadeler:
case 404:
case 500:
{
Log.v("Server responses","Unable to respond due to server error");
break;
}
case 401:
{
//regenerate token
}
case 200:
{
// log in user
break;
}
Bunu kullanarak, 401 yanıtı için oturum açma kullanıcı işlevini çağırmanıza gerek yoktur, çünkü belirteç yeniden oluşturulduğunda, çalışma zamanı durum 200'e atlar.
Diğer türdeki sayıları, ayı, sayımı kolayca ayırabilirsiniz.
Bu, bu durumda daha iyidir;
public static void spanishNumbers(String span){
span = span.toLowerCase().replace(" ", "");
switch (span){
case "1":
case "jan": System.out.println("uno"); break;
case "2":
case "feb": System.out.println("dos"); break;
case "3":
case "mar": System.out.println("tres"); break;
case "4":
case "apr": System.out.println("cuatro"); break;
case "5":
case "may": System.out.println("cinco"); break;
case "6":
case "jun": System.out.println("seis"); break;
case "7":
case "jul": System.out.println("seite"); break;
case "8":
case "aug": System.out.println("ocho"); break;
case "9":
case "sep": System.out.println("nueve"); break;
case "10":
case "oct": System.out.println("diez"); break;
}
}
Şu anda break
switch ifademde ihtiyacım olan proje üzerinde çalışıyorum, aksi takdirde kod çalışmaz. Benimle birlikte kalın ve break
size anahtar cümlenizde neden ihtiyacınız olduğuna dair iyi bir örnek vereceğim .
Biri kullanıcının bir sayı girmesini bekleyen, ikincisi onu hesaplamak için ve üçüncüsü toplamı yazdırmak için bekleyen üç durumunuz olduğunu hayal edin.
Bu durumda sahip olursunuz:
Devletler baktığınızda, talepleri sonucu sırası başlayacak isteyeyim state1 sonra, state3 ve nihayet state2 . Aksi takdirde, toplamı hesaplamadan yalnızca kullanıcıların girdilerini yazdıracağız. Tekrar açıklığa kavuşturmak için kullanıcının bir değer girmesini bekleriz, ardından toplamı hesaplar ve toplamı yazdırırız.
İşte örnek bir kod:
while(1){
switch(state){
case state1:
// Wait for user input code
state = state3; // Jump to state3
break;
case state2:
//Print the sum code
state = state3; // Jump to state3;
case state3:
// Calculate the sum code
state = wait; // Jump to state1
break;
}
}
Kullandığımız yoksa break
, bu düzen içinde çalıştırır state1 , state2 ve state3 . Ancak kullanarak break
, bu senaryodan kaçınıyoruz ve durum1, sonra durum3 ve son fakat en az değil durum2 ile başlamak için doğru prosedürde sipariş verebiliriz.
break
.