Tuesday, May 12, 2015

Java 7'de switch parametresinde String Kullanımı

Geç de olsa Java 7'de switch ifadesinde String tipinden değişkenler kullanabiliyoruz artık. Java 7 öncesinde, byte, short, int, char, enum tipinden değişkenler switch ifadesinde yer alabiliyordu. Bu tiplerin hepsi, enum ve String dışında, birer temel tip. Java 7 derleyicisinin String'i switch'de ele alış biçimine bir göz atalım. Bunun için aşağıdaki kodu javac derleyicisi ile derleyelim:
public class LostCharacters {

 public static void main(String[] args) {
  String name = args[0];
  switch (name) {
  case "Jack Shephard":
  case "Kate Austen":
  case "Hugo Reyes":
  case "James Ford":
  case "John Locke":
  case "Sayid Jarrah":
  case "Jin-Soo Kwon":
  case "Sun-Hwa Kwon":
  case "Claire Littleton":
  case "Charlie Pace":
  case "Michael Dawson":
  case "Walt Lloyd":
  case "Shannon Rutherford":
  case "Boone Carlyle":
  case "Rose Nadler":
  case "Christian Shephard":
  case "Danielle Rousseau":
  case "Bernard Nadler":
  case "Ana Lucia Cortez":
  case "Desmond Hume":
  case "Mr. Eko":
  case "Elizabeth Smith":
  case "Pierre Chang":
  case "Benjamin Linus":
  case "Penny Widmore":
  case "Alex Rousseau":
  case "Juliet Burke":
  case "Richard Alpert":
  case "Daniel Faraday":
   System.out.println(name + " is one of the Lost characters!");
   break;
  default:
   System.out.println(name + " is NOT a Lost character!");
  }
 }

}
Şimdi, yukarıdaki kodun derleyici tarafından nasıl bir çalıştırılabilir koda dönüştürüldüğüne bakalım: 
Compiled from "LostCharacters.java"
public class LostCharacters {
  public LostCharacters();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: aload_0       
       1: iconst_0      
       2: aaload        
       3: astore_1      
       4: aload_1       
       5: astore_2      
       6: iconst_m1     
       7: istore_3      
       8: aload_2       
       9: invokevirtual #2                  // Method java/lang/String.hashCode:()I
      12: lookupswitch  { // 29

           -1943924513: 595

           -1684978205: 625

           -1426063785: 298

           -1369432366: 550

           -1344062442: 340

            -878849615: 670

            -545297877: 655

            -459778184: 326

            -232853044: 256

                224946: 475

             142311738: 355

             233453844: 505

             273451333: 312

             430276635: 535

             843130897: 400

             953172067: 565

             959585900: 415

            1012622734: 580

            1013912041: 490

            1024487124: 430

            1199123051: 610

            1248045633: 385

            1401575792: 640

            1463165277: 520

            1508695859: 445

            1528121177: 460

            1812359415: 270

            1856610985: 284

            1931228609: 370
               default: 682
          }
     256: aload_2       
     257: ldc           #3                  // String Jack Shephard
     259: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     262: ifeq          682
     265: iconst_0      
     266: istore_3      
     267: goto          682
     270: aload_2       
     271: ldc           #5                  // String Kate Austen
     273: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     276: ifeq          682
     279: iconst_1      
     280: istore_3      
     281: goto          682
     284: aload_2       
     285: ldc           #6                  // String Hugo Reyes
     287: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     290: ifeq          682
     293: iconst_2      
     294: istore_3      
     295: goto          682
     298: aload_2       
     299: ldc           #7                  // String James Ford
     301: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     304: ifeq          682
     307: iconst_3      
     308: istore_3      
     309: goto          682
     312: aload_2       
     313: ldc           #8                  // String John Locke
     315: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     318: ifeq          682
     321: iconst_4      
     322: istore_3      
     323: goto          682
     326: aload_2       
     327: ldc           #9                  // String Sayid Jarrah
     329: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     332: ifeq          682
     335: iconst_5      
     336: istore_3      
     337: goto          682
     340: aload_2       
     341: ldc           #10                 // String Jin-Soo Kwon
     343: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     346: ifeq          682
     349: bipush        6
     351: istore_3      
     352: goto          682
     355: aload_2       
     356: ldc           #11                 // String Sun-Hwa Kwon
     358: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     361: ifeq          682
     364: bipush        7
     366: istore_3      
     367: goto          682
     370: aload_2       
     371: ldc           #12                 // String Claire Littleton
     373: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     376: ifeq          682
     379: bipush        8
     381: istore_3      
     382: goto          682
     385: aload_2       
     386: ldc           #13                 // String Charlie Pace
     388: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     391: ifeq          682
     394: bipush        9
     396: istore_3      
     397: goto          682
     400: aload_2       
     401: ldc           #14                 // String Michael Dawson
     403: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     406: ifeq          682
     409: bipush        10
     411: istore_3      
     412: goto          682
     415: aload_2       
     416: ldc           #15                 // String Walt Lloyd
     418: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     421: ifeq          682
     424: bipush        11
     426: istore_3      
     427: goto          682
     430: aload_2       
     431: ldc           #16                 // String Shannon Rutherford
     433: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     436: ifeq          682
     439: bipush        12
     441: istore_3      
     442: goto          682
     445: aload_2       
     446: ldc           #17                 // String Boone Carlyle
     448: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     451: ifeq          682
     454: bipush        13
     456: istore_3      
     457: goto          682
     460: aload_2       
     461: ldc           #18                 // String Rose Nadler
     463: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     466: ifeq          682
     469: bipush        14
     471: istore_3      
     472: goto          682
     475: aload_2       
     476: ldc           #19                 // String Christian Shephard
     478: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     481: ifeq          682
     484: bipush        15
     486: istore_3      
     487: goto          682
     490: aload_2       
     491: ldc           #20                 // String Danielle Rousseau
     493: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     496: ifeq          682
     499: bipush        16
     501: istore_3      
     502: goto          682
     505: aload_2       
     506: ldc           #21                 // String Bernard Nadler
     508: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     511: ifeq          682
     514: bipush        17
     516: istore_3      
     517: goto          682
     520: aload_2       
     521: ldc           #22                 // String Ana Lucia Cortez
     523: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     526: ifeq          682
     529: bipush        18
     531: istore_3      
     532: goto          682
     535: aload_2       
     536: ldc           #23                 // String Desmond Hume
     538: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     541: ifeq          682
     544: bipush        19
     546: istore_3      
     547: goto          682
     550: aload_2       
     551: ldc           #24                 // String Mr. Eko
     553: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     556: ifeq          682
     559: bipush        20
     561: istore_3      
     562: goto          682
     565: aload_2       
     566: ldc           #25                 // String Elizabeth Smith
     568: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     571: ifeq          682
     574: bipush        21
     576: istore_3      
     577: goto          682
     580: aload_2       
     581: ldc           #26                 // String Pierre Chang
     583: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     586: ifeq          682
     589: bipush        22
     591: istore_3      
     592: goto          682
     595: aload_2       
     596: ldc           #27                 // String Benjamin Linus
     598: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     601: ifeq          682
     604: bipush        23
     606: istore_3      
     607: goto          682
     610: aload_2       
     611: ldc           #28                 // String Penny Widmore
     613: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     616: ifeq          682
     619: bipush        24
     621: istore_3      
     622: goto          682
     625: aload_2       
     626: ldc           #29                 // String Alex Rousseau
     628: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     631: ifeq          682
     634: bipush        25
     636: istore_3      
     637: goto          682
     640: aload_2       
     641: ldc           #30                 // String Juliet Burke
     643: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     646: ifeq          682
     649: bipush        26
     651: istore_3      
     652: goto          682
     655: aload_2       
     656: ldc           #31                 // String Richard Alpert
     658: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     661: ifeq          682
     664: bipush        27
     666: istore_3      
     667: goto          682
     670: aload_2       
     671: ldc           #32                 // String Daniel Faraday
     673: invokevirtual #4                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
     676: ifeq          682
     679: bipush        28
     681: istore_3      
     682: iload_3       
     683: tableswitch   { // 0 to 28

                     0: 812

                     1: 812

                     2: 812

                     3: 812

                     4: 812

                     5: 812

                     6: 812

                     7: 812

                     8: 812

                     9: 812

                    10: 812

                    11: 812

                    12: 812

                    13: 812

                    14: 812

                    15: 812

                    16: 812

                    17: 812

                    18: 812

                    19: 812

                    20: 812

                    21: 812

                    22: 812

                    23: 812

                    24: 812

                    25: 812

                    26: 812

                    27: 812

                    28: 812
               default: 840
          }
     812: getstatic     #33                 // Field java/lang/System.out:Ljava/io/PrintStream;
     815: new           #34                 // class java/lang/StringBuilder
     818: dup           
     819: invokespecial #35                 // Method java/lang/StringBuilder."<init>":()V
     822: aload_1       
     823: invokevirtual #36                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     826: ldc           #37                 // String  is one of the Lost characters!
     828: invokevirtual #36                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     831: invokevirtual #38                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     834: invokevirtual #39                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     837: goto          865
     840: getstatic     #33                 // Field java/lang/System.out:Ljava/io/PrintStream;
     843: new           #34                 // class java/lang/StringBuilder
     846: dup           
     847: invokespecial #35                 // Method java/lang/StringBuilder."<init>":()V
     850: aload_1       
     851: invokevirtual #36                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     854: ldc           #40                 // String  is NOT a Lost character!
     856: invokevirtual #36                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     859: invokevirtual #38                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     862: invokevirtual #39                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     865: return        
}
Bu kodu tersine mühendislik ile çözecek olursak aşağıdaki kodu elde ederiz:
import java.io.PrintStream;

public class CompilerLostCharacters {
 public static void main(String[] paramArrayOfString) {
  String str1 = paramArrayOfString[0];
  String str2 = str1;
  int i = -1;
  switch (str2.hashCode()) {
  case -232853044:
   if (str2.equals("Jack Shephard"))
    i = 0;
   break;
  case 1812359415:
   if (str2.equals("Kate Austen"))
    i = 1;
   break;
  case 1856610985:
   if (str2.equals("Hugo Reyes"))
    i = 2;
   break;
  case -1426063785:
   if (str2.equals("James Ford"))
    i = 3;
   break;
  case 273451333:
   if (str2.equals("John Locke"))
    i = 4;
   break;
  case -459778184:
   if (str2.equals("Sayid Jarrah"))
    i = 5;
   break;
  case -1344062442:
   if (str2.equals("Jin-Soo Kwon"))
    i = 6;
   break;
  case 142311738:
   if (str2.equals("Sun-Hwa Kwon"))
    i = 7;
   break;
  case 1931228609:
   if (str2.equals("Claire Littleton"))
    i = 8;
   break;
  case 1248045633:
   if (str2.equals("Charlie Pace"))
    i = 9;
   break;
  case 843130897:
   if (str2.equals("Michael Dawson"))
    i = 10;
   break;
  case 959585900:
   if (str2.equals("Walt Lloyd"))
    i = 11;
   break;
  case 1024487124:
   if (str2.equals("Shannon Rutherford"))
    i = 12;
   break;
  case 1508695859:
   if (str2.equals("Boone Carlyle"))
    i = 13;
   break;
  case 1528121177:
   if (str2.equals("Rose Nadler"))
    i = 14;
   break;
  case 224946:
   if (str2.equals("Christian Shephard"))
    i = 15;
   break;
  case 1013912041:
   if (str2.equals("Danielle Rousseau"))
    i = 16;
   break;
  case 233453844:
   if (str2.equals("Bernard Nadler"))
    i = 17;
   break;
  case 1463165277:
   if (str2.equals("Ana Lucia Cortez"))
    i = 18;
   break;
  case 430276635:
   if (str2.equals("Desmond Hume"))
    i = 19;
   break;
  case -1369432366:
   if (str2.equals("Mr. Eko"))
    i = 20;
   break;
  case 953172067:
   if (str2.equals("Elizabeth Smith"))
    i = 21;
   break;
  case 1012622734:
   if (str2.equals("Pierre Chang"))
    i = 22;
   break;
  case -1943924513:
   if (str2.equals("Benjamin Linus"))
    i = 23;
   break;
  case 1199123051:
   if (str2.equals("Penny Widmore"))
    i = 24;
   break;
  case -1684978205:
   if (str2.equals("Alex Rousseau"))
    i = 25;
   break;
  case 1401575792:
   if (str2.equals("Juliet Burke"))
    i = 26;
   break;
  case -545297877:
   if (str2.equals("Richard Alpert"))
    i = 27;
   break;
  case -878849615:
   if (str2.equals("Daniel Faraday"))
    i = 28;
   break;
  }
  switch (i) {
  case 0:
  case 1:
  case 2:
  case 3:
  case 4:
  case 5:
  case 6:
  case 7:
  case 8:
  case 9:
  case 10:
  case 11:
  case 12:
  case 13:
  case 14:
  case 15:
  case 16:
  case 17:
  case 18:
  case 19:
  case 20:
  case 21:
  case 22:
  case 23:
  case 24:
  case 25:
  case 26:
  case 27:
  case 28:
   System.out.println(str1 + " is one of the Lost characters!");
   break;
  default:
   System.out.println(str1 + " is NOT a Lost character!");
  }
 }

}
Üretilen kodda çok özel bir durumla karşılaşmadık. Beklediğimiz gibi derleyici, önce String sabitlerin hashCode() çağrısından dönen int tipinde özet değerini (=hash value),  case sabiti olarak kullandı. Özet değeri, farklı iki String için aynı olabilir. Bu nedenle, derleyicinin, özet değerlerin eşitliği ile yetinmediğini ve equals() çağrısını kullanarak içeriklerinin de eşitliğini test ettiğini görüyoruz. Genel olarak, eğer equals() çağrısı true dönüyorsa, nesnelerin özet değerleri aynıdır. Ancak equals() çağrısı false dönüyorsa, özet değerleri aynı olabilir. İlginç bir şekilde, biz bir tane switch yazmış görünsek de, gerçekte iki farklı switch ifadesinin çalıştığını anlıyoruz. İlk switch ifadesinde case sabitleri özet fonksiyonundan gelen değerler. Birinci switch ifadesinin her bir case tanımında break ifadesi kullanıldığını görüyoruz. Burada i gibi tam sayı değişkene, her bir case bloğunda ardışıl olarak artan bir sabit atanıyor.
switch ifadesinde String kullanımında ilginç durum, String sabitlerin özet değerinin aynı olması durumunda yaşanıyor:
public class TestStringInSwitch {

 public static void main(String... args) {
  String name = args[0];
  System.out.println("AaAa".hashCode());
         System.out.println("BBBB".hashCode());
         System.out.println("AaBB".hashCode());
         System.out.println("BBAa".hashCode());
  switch (name) {
  case "AaAa":
   System.err.println("Hello Moon!");
   break;
  case "BBBB":
   System.err.println("Hello Mars!");
   break;
  case "AaBB":
   System.err.println("Hello World!");
   break;
  case "BBAa":
   System.err.println("Hello Sun!");
   break;
  default:
   System.err.println("Hello UFO!");
   break;
  }
 }

}
Burada, karakter katarlarının hepsi ("AaAa", "BBBB", "AaBB", "BBAa") için özet değeri 2031744'dür. Bu durumda, derleyici aşağıdaki çalıştırılabilir kodu üretir:
import java.io.PrintStream;

public class CompilerTestStringInSwitch {
 public static void main(String... paramVarArgs) {
  String str1 = paramVarArgs[0];
  System.out.println("AaAa".hashCode());
  System.out.println("BBBB".hashCode());
  System.out.println("AaBB".hashCode());
  System.out.println("BBAa".hashCode());
  String str2 = str1;
  int i = -1;
  switch (str2.hashCode()) {
   case 2031744:
   if (str2.equals("BBAa"))
    i = 3;
   else if (str2.equals("AaBB"))
    i = 2;
   else if (str2.equals("BBBB"))
    i = 1;
   else if (str2.equals("AaAa"))
    i = 0;
                 break;
  }
  switch (i) {
   case 0:
   System.err.println("Hello Moon!");
   break;
                 case 1:
   System.err.println("Hello Mars!");   
                 break;
                 case 2:
   System.err.println("Hello World!");   
                 break;
                 case 3:
   System.err.println("Hello Sun!");   
                 break;
   default:
   System.err.println("Hello UFO!");
  }
 }
}
Eğer şansızlık eseri case sabitlerinin tümü için özet değeri aynı olursa, switch, iç içe if-else-if ifadelerine dönüşüyor. Bu durumu biz yapay olarak yarattık. Gerçekte, bu durumla karşılaşmanız imkansız değilse bile çok düşük bir ihtimal!