Bu işlev daha sonraki bir Java sürümüne eklenecek mi?
Birisi Java'nın switch
ifadesinin çalışma biçiminde olduğu gibi neden bunu yapamayacağımı açıklayabilir mi?
"Don't hold your breath."
lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179
Bu işlev daha sonraki bir Java sürümüne eklenecek mi?
Birisi Java'nın switch
ifadesinin çalışma biçiminde olduğu gibi neden bunu yapamayacağımı açıklayabilir mi?
"Don't hold your breath."
lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179
Yanıtlar:
Vakalarla ilgili anahtar bildirimleri String
, Java SE 7'de , ilk istendiklerinden en az 16 yıl sonra uygulanmıştır. Gecikmenin açık bir nedeni belirtilmedi, ancak muhtemelen performansla ilgisi vardı.
Bu özellik şimdi javac
bir "şekersizleştirici" işlemle uygulanmaktadır; bildirimlerde String
sabitleri kullanan temiz, yüksek düzeyli bir sözdizimi case
derleme zamanında bir kalıbı izleyen daha karmaşık koda genişletilir. Ortaya çıkan kod, her zaman var olan JVM talimatlarını kullanır.
Kılıflı A switch
, String
derleme sırasında iki anahtara çevrilir. Birincisi, her bir dizeyi benzersiz bir tamsayı ile eşler - orijinal anahtardaki konumu. Bu, önce etiketin karma kodunu açarak yapılır. Karşılık gelen durum if
dize eşitliğini test eden bir ifadedir; karma üzerinde çarpışmalar varsa, test basamaklıdır if-else-if
. İkinci anahtar orijinal kaynak kodundaki aynayı yansıtır, ancak büyük / küçük harf etiketlerini karşılık gelen konumlarıyla değiştirir. Bu iki aşamalı işlem, orijinal anahtarın akış kontrolünün korunmasını kolaylaştırır.
Daha fazla teknik derinlik için switch
, anahtar ifadelerinin derlenmesinin açıklandığı JVM Spesifikasyonuna başvurabilirsiniz . Özetle, vakalar tarafından kullanılan sabitlerin genişliğine bağlı olarak, bir anahtar için kullanılabilecek iki farklı JVM talimatı vardır. Her ikisi de verimli bir şekilde yürütmek için her durum için tamsayı sabitlerinin kullanılmasına bağlıdır.
Sabitler yoğunsa, bir yönerge işaretçileri tablosuna (yönerge) bir dizin olarak (en düşük değeri çıkardıktan sonra) kullanılırlar tableswitch
.
Sabitler seyrekse, doğru durum için ikili bir arama yapılır - lookupswitch
talimat.
Nesnelerin switch
üzerindeki şekerden arındırma String
işleminde, her iki yönerge de kullanılabilir. lookupswitch
Karma kodları ilk geçiş durumunda orijinal konumunu bulmak için uygundur. Ortaya çıkan ordinal, a tableswitch
.
Her iki yönerge de derleme zamanında her bir duruma atanan tamsayı sabitlerinin sıralanmasını gerektirir. Çalışma zamanında, O(1)
performansı tableswitch
genellikle performansından daha iyi görünse O(log(n))
de lookupswitch
, tablonun uzay-zaman dengesini haklı çıkarmak için yeterince yoğun olup olmadığını belirlemek için biraz analiz gerektirir. Bill Venners , diğer Java akış kontrol talimatlarına başlık altında bir bakışla birlikte, bunu daha ayrıntılı bir şekilde ele alan harika bir makale yazdı .
JDK 7'den önce, enum
bir String
tabanlı anahtara yaklaşabiliyordu . Bu , derleyici tarafından üretilen her türde statikvalueOf
yöntemi kullanır enum
. Örneğin:
Pill p = Pill.valueOf(str);
switch(p) {
case RED: pop(); break;
case BLUE: push(); break;
}
Pill
eylemde str
bulunmaya çalışıyorsanız, başka bir şey tercih ediyorsanız, str
KIRMIZI, MAVİ aralığın dışındaki değerleri ele almanıza valueOf
veya adıyla karşı bir eşleşmeyi manuel olarak kontrol etmenize izin vermez . gereksiz numaralar ekleyen her numaralandırma türü. Deneyimlerime göre, ancak valueOf
daha sonra String değerinin tipesafe bir temsili gerekiyorsa bir numaralandırmaya dönüştürmek için kullanmak mantıklı oldu.
(hash >> x) & ((1<<y)-1)
dize sayısının iki katından daha az olan (veya en azından bundan daha büyük değil). hashCode
(1<<y)
Kodunuzda bir String'i açabileceğiniz bir yer varsa, String'i açabileceğiniz olası değerlerin bir numaralandırması olarak yeniden düzenlemek daha iyi olabilir. Tabii ki, sahip olabileceğiniz Dizelerin potansiyel değerlerini numaralandırmada istenebilecek veya istenmeyecek değerlerle sınırlandırırsınız.
Tabii ki numaralandırma 'other' için bir giriş ve bir fromString (String) yöntemi olabilir, o zaman
ValueEnum enumval = ValueEnum.fromString(myString);
switch (enumval) {
case MILK: lap(); break;
case WATER: sip(); break;
case BEER: quaff(); break;
case OTHER:
default: dance(); break;
}
Aşağıda, özel bir yöntem kullanmak yerine java enum's kullanarak JeeBee'nin gönderisine dayanan tam bir örnek verilmiştir.
Java SE 7 ve sonraki sürümlerinde, bunun yerine switch ifadesinin ifadesinde bir String nesnesi kullanabileceğinizi unutmayın.
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String current = args[0];
Days currentDay = Days.valueOf(current.toUpperCase());
switch (currentDay) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
System.out.println("boring");
break;
case THURSDAY:
System.out.println("getting better");
case FRIDAY:
case SATURDAY:
case SUNDAY:
System.out.println("much better");
break;
}
}
public enum Days {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
}
Tamsayılara dayalı anahtarlar çok verimli koda göre optimize edilebilir. Diğer veri türüne dayalı anahtarlar yalnızca bir dizi if () ifadesine derlenebilir.
Bu nedenle C & C ++ yalnızca tamsayı türlerinde anahtarlara izin verir, çünkü diğer türlerle anlamsızdır.
C # tasarımcıları, hiçbir avantaj olmasa bile, stilin önemli olduğuna karar verdiler.
Java tasarımcıları görünüşe göre C tasarımcıları gibi düşündüler.
String
1.7'den beri doğrudan kullanım için bir örnek de gösterilebilir:
public static void main(String[] args) {
switch (args[0]) {
case "Monday":
case "Tuesday":
case "Wednesday":
System.out.println("boring");
break;
case "Thursday":
System.out.println("getting better");
case "Friday":
case "Saturday":
case "Sunday":
System.out.println("much better");
break;
}
}
James Curran özünde şöyle diyor: "Tamsayılara dayalı anahtarlar çok verimli koda göre optimize edilebilir. Diğer veri türüne dayalı anahtarlar yalnızca if () ifadeleri dizisine derlenebilir. Bu nedenle C & C ++ yalnızca tamsayı türlerinde anahtarlara izin verir, çünkü diğer türlerle anlamsızdı. "
Benim düşüncem ve sadece bu, ilkel olmayanları açmaya başlar başlamaz "eşittir" e karşı = = "düşünmeye başlamanız gerektiğidir. İlk olarak, iki dizeyi karşılaştırmak, yukarıda belirtilen performans sorunlarına ek olarak oldukça uzun bir prosedür olabilir. İkincisi, dizeleri açma durumunda, durumu görmezden gelen dizeleri açma, yerel ayarları göz önünde bulundurarak / görmezden gelme, regex tabanlı dizeleri açma talepleri olacaktır .... Ben çok zaman kazandıran bir karar onaylamak dil geliştiricileri programcılar için küçük bir zaman pahasına.
matched
ve not matched
. (Yine de [adlandırılmış] gruplar / vb. Şeyleri hesaba katmamak.)
Yukarıdaki iyi argümanların yanı sıra, bugün birçok insanın switch
Java'nın yordamsal geçmişinin eski bir kalıntısı olarak göreceğini de ekleyeceğim (C zamanlarına kadar).
Bu görüşü tam olarak paylaşmıyorum switch
, bazı durumlarda yararlı olabileceğini düşünüyorum , en azından hızı nedeniyle ve yine de else if
bazı kodlarda gördüğüm basamaklı sayısal serilerden daha iyi ...
Ama gerçekten, bir anahtara ihtiyacınız olan duruma bakmaya ve bunun daha fazla OO ile değiştirilip değiştirilemeyeceğine bakmaya değer. Örneğin, Java 1.5+, belki HashTable veya başka bir koleksiyondaki (bazen pişmanlık duyuyorum (anonim), Lua'da olduğu gibi, anahtar - veya JavaScript içermeyen), hatta polimorfizm gibi (anonim) işlevlerimiz yok.
JDK7 veya üstünü kullanmıyorsanız hashCode()
, simüle etmek için kullanabilirsiniz . Çünkü String.hashCode()
genellikle farklı dizeleri için farklı değerler döndürür ve her zaman eşit dizeleri eşit değerleri döndürür, oldukça güvenilir (Farklı dizeleri olduğunu olabilir @Lii gibi bir açıklamada belirtildiği gibi aynı hash kodu üretmek "FB"
ve "Ea"
bakın) belgelerinde .
Yani, kod şöyle görünecektir:
String s = "<Your String>";
switch(s.hashCode()) {
case "Hello".hashCode(): break;
case "Goodbye".hashCode(): break;
}
Bu şekilde, teknik olarak bir int
.
Alternatif olarak, aşağıdaki kodu kullanabilirsiniz:
public final class Switch<T> {
private final HashMap<T, Runnable> cases = new HashMap<T, Runnable>(0);
public void addCase(T object, Runnable action) {
this.cases.put(object, action);
}
public void SWITCH(T object) {
for (T t : this.cases.keySet()) {
if (object.equals(t)) { // This means that the class works with any object!
this.cases.get(t).run();
break;
}
}
}
}
case
ifadeler her zaman sabit değerler olması gibi, bu derler şaşırdım ve String.hashCode()
böyle değil (pratikte JVM'ler arasında hiç değişmemiş olsa bile).
case
deyim değerlerinin derleme zamanında belirlenebilir olması gerekmez , bu yüzden iyi çalışır.
Yıllardır bunun için (n açık kaynak) önişlemci kullanıyoruz.
//#switch(target)
case "foo": code;
//#end
Önceden işlenmiş dosyalar Foo.jpp olarak adlandırılır ve bir karınca komut dosyası ile Foo.java'ya işlenir.
Avantajı, 1.0'da çalışan Java'ya işlenmesidir (genellikle yalnızca 1.4'e kadar destekledik). Ayrıca bunu (dizi anahtarları) numaralandırma veya diğer geçici çözümlerle doldurmaya kıyasla yapmak çok daha kolaydı - kodun okunması, bakımı ve anlaşılması çok daha kolaydı. IIRC (bu noktada istatistik veya teknik akıl yürütme sağlayamaz), aynı zamanda doğal Java eşdeğerlerinden daha hızlıydı.
Dezavantajları Java'yı düzenlemiyor olmanızdır, bu yüzden biraz daha fazla iş akışı (düzenleme, işleme, derleme / test etme) artı bir IDE, biraz kıvrımlı olan Java'ya geri bağlanacaktır (anahtar, if / else mantık adımlarından oluşan bir dizi haline gelir) ve anahtar kutusu sırası korunmaz.
1.7+ için tavsiye etmem ama daha önce JVM'leri hedefleyen Java programlamak istiyorsanız yararlıdır (Joe public nadiren en son yüklü olduğundan).
SVN'den alabilir veya çevrimiçi kodlara göz atabilirsiniz . Olduğu gibi inşa etmek için EBuild'e ihtiyacınız olacak .
Diğer yanıtlar bunun Java 7'ye eklendiğini ve önceki sürümler için geçici çözümler sağladığını söyledi. Bu cevap "neden"
Java, C ++ 'ın aşırı karmaşıklıklarına bir tepkiydi. Basit ve temiz bir dil olacak şekilde tasarlanmıştır.
String, dilde biraz özel durum işleme aldı, ancak tasarımcıların özel kasa ve sözdizimsel şeker miktarını minimumda tutmaya çalıştığı açık.
telleri açmak basit ilkel tipler olmadığı için kaputun altında oldukça karmaşıktır. Java'nın tasarlandığı sırada ortak bir özellik değildi ve minimalist tasarıma gerçekten uymuyor. Özellikle dizeler için özel durum == 'a karar vermedikleri için, ==' ın olmadığı durumlarda davanın çalışması biraz garip olurdu.
1.0 ve 1.4 arasında dilin kendisi hemen hemen aynı kaldı. Java'daki geliştirmelerin çoğu kütüphane tarafındaydı.
Her şey Java 5 ile değişti, dil büyük ölçüde genişletildi. Ek uzantılar 7 ve 8 sürümlerinde izledi. Ben bu tutum değişikliği C # yükselişi tarafından yönlendirilmesi bekliyoruz
JEP 354: JDK-13'teki Anahtar İfadeleri (Önizleme) veJDK-14'teki Anahtar İfadeleri (Standart) , anahtar ifadesini ifade olarak kullanılabilmesi içingenişletir.
Şimdi yapabilirsin:
case L ->
):
Bir "case L ->" anahtar etiketinin sağındaki kod, bir ifade, bir blok ya da (kolaylık olması açısından) bir throw ifadesi ile sınırlıdır.
Bir anahtar ifadesinden bir değer vermek için
break
with value ifadesi, biryield
ifade lehine bırakılır .
Cevaplardan ( 1 , 2 ) demo şu şekilde görünebilir:
public static void main(String[] args) {
switch (args[0]) {
case "Monday", "Tuesday", "Wednesday" -> System.out.println("boring");
case "Thursday" -> System.out.println("getting better");
case "Friday", "Saturday", "Sunday" -> System.out.println("much better");
}
Çok hoş değil, ama Java 6 ve feryat için başka bir yol:
String runFct =
queryType.equals("eq") ? "method1":
queryType.equals("L_L")? "method2":
queryType.equals("L_R")? "method3":
queryType.equals("L_LR")? "method4":
"method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);
Groovy'de bir esinti; Harika kavanozu gömdüm ve groovy
Java'da yapmak için bıkkın bulduğum tüm bu şeyleri ve daha fazlasını yapmak için bir yardımcı program sınıfı oluşturdum (çünkü kuruluşta Java 6 kullanarak sıkışıp kaldım.)
it.'p'.each{
switch (it.@name.text()){
case "choclate":
myholder.myval=(it.text());
break;
}}...
İntellij kullandığınızda şunlara da bakın:
Dosya -> Proje Yapısı -> Proje
Dosya -> Proje Yapısı -> Modüller
Birden fazla modülünüz olduğunda, modül sekmesinde doğru dil seviyesini ayarladığınızdan emin olun.
public class StringSwitchCase {
public static void main(String args[]) {
visitIsland("Santorini");
visitIsland("Crete");
visitIsland("Paros");
}
public static void visitIsland(String island) {
switch(island) {
case "Corfu":
System.out.println("User wants to visit Corfu");
break;
case "Crete":
System.out.println("User wants to visit Crete");
break;
case "Santorini":
System.out.println("User wants to visit Santorini");
break;
case "Mykonos":
System.out.println("User wants to visit Mykonos");
break;
default:
System.out.println("Unknown Island");
break;
}
}
}