`
leonzhx
  • 浏览: 794006 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Zz Java 7 新特性 -- 实战篇

阅读更多

  “举世瞩目”的java 7近日发布,oracle网站上列出了java 语言的新特性http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html,最近出差,晚上闲来无事,将这些java语言的新特性试了下,very cool。 
    下面介绍了java 7的一些新特性,翻译自oracle网站,结合自己的实战。对Java 7研究不深,以下内容有对有错,欢迎大家批评指正,共同学习! 

    环境: ubuntu 11.04+eclipse 3.8 
    本来是用netbeans7.0.1,可是非常难用(不习惯 netBeans),加之用了几天之后,eclipse3.8推出,也支持java7,就切换到了更熟悉的eclipse下。顺便说一句,ubuntu11.04界面做的挺不错的,非常喜欢(附图是win 7下的无缝模式)。 

    java 7下载: http://www.oracle.com/technetwork/java/javase/downloads/index.html 
    eclipse 3.8下载: http://download.eclipse.org/eclipse/downloads/drops/S-3.8M1-201108031800/ 
    Netbeans 7.0.1 下载:http://netbeans.org/downloads/start.html?platform=linux&lang=zh_CN&option=javaee 


    特性1:二进制字面值(Binary Literals) 

    在java7里,整形(byte,short,int,long)类型的值可以用二进制类型来表示了,在使用二进制的值时,需要在前面加上ob或oB,看代码 
   

Java代码  收藏代码
  1.        //b 大小写都可以  
  2. int a = 0b01111_00000_11111_00000_10101_01010_10;  
  3. short b = (short)0b01100_00000_11111_0;  
  4. byte c = (byte)0B0000_0001;  
  5.      



    其次,二进制同十进制和十六进制相比,可以一目了然的看出数据间的关系。例如下面这个数组中展示了每次移动一位后数字的变化。 
    

Java代码  收藏代码
  1. public static final int[] phases = {  
  2.    0b00110001,  
  3.    0b01100010,  
  4.    0b11000100,  
  5.    0b10001001,  
  6.    0b00010011,  
  7.    0b00100110,  
  8.    0b01001100,  
  9.    0b10011000  
  10. }  


如果用十六进制来表示的,它们之间的关系就无法一眼看出来了。 

Java代码  收藏代码
  1. public static final int[] phases = {  
  2.  0x310x620xC40x890x130x260x4C0x98  
  3. }  



    特性2:数字变量对下划线_的支持 

    你可以在数值类型的变量里添加下滑线,除了以下的几个地方不能添加: 
      数字的开头和结尾 
      小数点前后 
      F或者L前 
      需要出现string类型值的地方(针对用0x或0b表示十六进制和二进制,参考第一点),比如0x101,不能用0_x101 
   

Java代码  收藏代码
  1. int num = 1234_5678_9;  
  2. float num2 = 222_33F;  
  3. long num3 = 123_000_111L;  
  4.   
  5. //下面的不行  
  6. //数字开头和结尾  
  7. int nu = _123;  
  8. int nu = 123_;  
  9. //小数点前后  
  10. float f = 123_.12;  
  11. float f = 123._12;  
  12. //F或者L前  
  13. long l = 123_L;  
  14. float f = 123_F;  
  15. //需要出现String的地方  
  16. int num = 0_b123;  
  17. float f = 0_x123F;  



    这个,我个人觉得没什么实际作用,只是可以提升代码的可读性。 

    特性3:switch 对String的支持 

    这个大家期待很久了,switch终于支持String了 
    

Java代码  收藏代码
  1. public static void first() {  
  2.     //项目状态  
  3.     String status = "approval";  
  4.     //我们之前经常根据项目状态不同来进行不同的操作  
  5.     //目前已经换成enum类型  
  6.       
  7.     switch (status) {  
  8.         case "shouli":  
  9.             System.out.println("状态是受理");  
  10.             break;  
  11.         case "approval":  
  12.             System.out.println("状态是审批");  
  13.             break;  
  14.         case "finish":  
  15.             System.out.println("状态是结束");  
  16.             break;  
  17.         default:  
  18.             System.out.println("状态未知");  
  19.     }  
  20. }  



    每个case是使用String的equals方法来进行比较的,对大小写敏感。 

    和一连串的if-else-then想比,使用switch来计较String,Java编译器会生成更加有效的字节码,写一个例子测试一下。 

Java代码  收藏代码
  1. public static void second() {  
  2.       String status = "approval";  
  3.       if ("shouli".equals(status)) {  
  4.           System.out.println("状态是受理");  
  5.       } else if ("approval".equals(status)) {  
  6.           System.out.println("状态是审批");  
  7.       } else if ("finish".equals(status)) {  
  8.           System.out.println("状态是结束");  
  9.       } else {  
  10.           System.out.println("状态未知");  
  11.       }  
  12. }  


使用javap之后,生成字节码如下: 
switch 

Java代码  收藏代码
  1. public static void first();  
  2.     Code:  
  3.        0: ldc           #2                  // String approval  
  4.        2: astore_0        
  5.        3: aload_0         
  6.        4: astore_1        
  7.        5: iconst_m1       
  8.        6: istore_2        
  9.        7: aload_1         
  10.        8: invokevirtual #3                  // Method java/lang/String.hashCode:()I  
  11.       11: lookupswitch  { // 3  
  12.            -127444260572  
  13.             -90314605644  
  14.             118524473958  
  15.                default83  
  16.           }  
  17.       44: aload_1         
  18.       45: ldc           #4                  // String shouli  
  19.       47: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  20.       50: ifeq          83  
  21.       53: iconst_0        
  22.       54: istore_2        
  23.       55goto          83  
  24.       58: aload_1         
  25.       59: ldc           #2                  // String approval  
  26.       61: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  27.       64: ifeq          83  
  28.       67: iconst_1        
  29.       68: istore_2        
  30.       69goto          83  
  31.       72: aload_1         
  32.       73: ldc           #6                  // String finish  
  33.       75: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  34.       78: ifeq          83  
  35.       81: iconst_2        
  36.       82: istore_2        
  37.       83: iload_2         
  38.       84: tableswitch   { // 0 to 2  
  39.                      0112  
  40.                      1123  
  41.                      2134  
  42.                default145  
  43.           }  
  44.      112: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  45.      115: ldc           #8                    
  46.      117: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  47.      120goto          153  
  48.      123: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  49.      126: ldc           #10                   
  50.      128: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  51.      131goto          153  
  52.      134: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  53.      137: ldc           #11                   
  54.      139: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  55.      142goto          153  
  56.      145: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  57.      148: ldc           #12                  
  58.      150: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  59.      153return    



   用if-else串生成的字节码 
  

Java代码  收藏代码
  1.  public static void second();  
  2. de:  
  3.  0: ldc           #2                  // String approval  
  4.  2: astore_0        
  5.  3: ldc           #4                  // String shouli  
  6.  5: aload_0         
  7.  6: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  8.  9: ifeq          23  
  9. 12: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  10. 15: ldc           #8                    
  11. 17: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  12. 20goto          71  
  13. 23: ldc           #2                  // String approval  
  14. 25: aload_0         
  15. 26: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  16. 29: ifeq          43  
  17. 32: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  18. 35: ldc           #10                   
  19. 37: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  20. 40goto          71  
  21. 43: ldc           #6                  // String finish  
  22. 45: aload_0         
  23. 46: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z  
  24. 49: ifeq          63  
  25. 52: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  26. 55: ldc     
  27. 57: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  28. 60goto          71  
  29. 63: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;  
  30. 66: ldc           #12                   
  31. 68: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V  
  32. 71return   


   网上说,用switch之后比用if-else生成的字节码更有效一些,不过目前至少从长度上来说,switch还是长一些 
   

   特性4:try-with-resources 声明 

   try-with-resources 是一个定义了一个或多个资源的try 声明,这个资源是指程序处理完它之后需要关闭它的对象。try-with-resources 确保每一个资源在处理完成后都会被关闭。 
可以使用try-with-resources的资源有: 
任何实现了java.lang.AutoCloseable 接口和java.io.Closeable 接口的对象。 

来看例子: 

Java代码  收藏代码
  1.   public static String readFirstLineFromFile(String path) throws IOException {  
  2.      try (BufferedReader br = new BufferedReader(new FileReader(path))) {  
  3.        return br.readLine();  
  4.      }  
  5. }  


   在java 7 以及以后的版本里,BufferedReader实现了java.lang.AutoCloseable接口。 
  

Java代码  收藏代码
  1.        try (Closeable obj = new Closeable() {  
  2.        @Override  
  3.        public void close() throws IOException {  
  4.       // do something  
  5.         }  
  6. }) {  
  7. // do something  
  8. }  
  9.   
  10. try (AutoCloseable obj = new AutoCloseable() {  
  11.         @Override  
  12.     public void close() throws IOException {  
  13.        // do something  
  14.     }  
  15. }) {  
  16.        // do something  
  17. }   
  18.     


   
   由于BufferedReader定义在try-with-resources 声明里,无论try语句正常还是异常的结束,它都会自动的关掉。而在java7以前,你需要使用finally块来关掉这个对象。 
  

Java代码  收藏代码
  1. public static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {  
  2.    BufferedReader br = new BufferedReader(new FileReader(path));  
  3.    try {  
  4.       return br.readLine();  
  5.    } finally {  
  6.       if (br != null) br.close();  
  7.    }  
  8.  }  



   然而,如果 readLine() 和 close() 这两个方法都抛出异常,那么readFirstLineFromFileWithFinallyBlock 方法只会抛出后面部分也就是finally块中的内容,try块中的异常就被抑制了,对于我们的程序来说,这显然不是一种好的方式。 
   而在java 7中,无论是try块还是try-with-resource中抛出异常,readFirstLineFromFile会捕捉到try块的异常,try-with-resources中中异常被禁止了。在java 7 中,你能捕捉到被禁止的异常。getSuppressed()方法被用来检索被抛出异常抑制的其他异常。同样,Throwable类中添加了一个新的构造函数,而这个类可用来启用或禁用对异常的抑制(仅Oracle JDK)。 

  
   另外,一个try-with-resourcse声明了可以包含多个对象的声明,用分号隔开,和声明一个对象相同,会在结束后自动调用close方法,调用顺序和生命顺序相反。 
  

Java代码  收藏代码
  1. try (  
  2.   java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);  
  3.   java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)  
  4. ) {  
  5.   // do something  
  6. }  


  
  此外,try-with-resources 可以跟catch和finally,catch和finally的是在try-with-resources里声明的对象关闭之后才执行的。 


   特性5:捕获多种异常并用改进后的类型检查来重新抛出异常 
   
   1、捕获多种异常 

   在Java SE7里,一个catch可以捕获多个异常,这样可以减少重复代码。每个异常之间用 | 隔开。 
  

Java代码  收藏代码
  1. public static void first(){  
  2.     try {  
  3. BufferedReader reader = new BufferedReader(new FileReader(""));  
  4. Connection con = null;  
  5. Statement stmt = con.createStatement();  
  6.     } catch (IOException | SQLException e) {  
  7. //捕获多个异常,e就是final类型的  
  8. e.printStackTrace();  
  9.     }  
  10. }  


   而在Java SE6以前,需要这样写 
  

Java代码  收藏代码
  1.       public static void second() {  
  2.     try {  
  3.         BufferedReader reader = new BufferedReader(new FileReader(""));  
  4.         Connection con = null;  
  5.         Statement stmt = con.createStatement();  
  6.     } catch (IOException e) {  
  7.         e.printStackTrace();  
  8.     } catch (SQLException e) {  
  9.         e.printStackTrace();  
  10.     }  
  11. }  
  12.     


   注意,如果一个catch处理了多个异常,那么这个catch的参数默认就是final的,你不能在catch块里修改它的值。 
   另外,用一个catch处理多个异常,比用多个catch每个处理一个异常生成的字节码要更小更高效。 

   使用一个catch生成的字节码 
  

Java代码  收藏代码
  1.  public static void first();  
  2. Code:  
  3.    0new           #2                  // class java/io/BufferedReader  
  4.    3: dup             
  5.    4new           #3                  // class java/io/FileReader  
  6.    7: dup             
  7.    8: ldc           #4                  // String   
  8.   10: invokespecial #5                  // Method java/io/FileReader."<init>":(Ljava/lang/String;)V  
  9.   13: invokespecial #6                  // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V  
  10.   16: astore_0        
  11.   17: aconst_null     
  12.   18: astore_1        
  13.   19: aload_1         
  14.   20: invokeinterface #7,  1            // InterfaceMethod java/sql/Connection.createStatement:()Ljava/sql/Statement;  
  15.   25: astore_2        
  16.   26goto          34  
  17.   29: astore_0        
  18.   30: aload_0         
  19.   31: invokevirtual #10                 // Method java/lang/Exception.printStackTrace:()V  
  20.   34return          
  21. Exception table:  
  22.    from    to  target type  
  23.        0    26    29   Class java/io/IOException  
  24.        0    26    29   Class java/sql/SQLException  



   使用两个catch生成的字节码 
  

Java代码  收藏代码
  1.  public static void second();  
  2. Code:  
  3.    0new           #2                  // class java/io/BufferedReader  
  4.    3: dup             
  5.    4new           #3                  // class java/io/FileReader  
  6.    7: dup             
  7.    8: ldc           #4                  // String   
  8.   10: invokespecial #5                  // Method java/io/FileReader."<init>":(Ljava/lang/String;)V  
  9.   13: invokespecial #6                  // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V  
  10.   16: astore_0        
  11.   17: aconst_null     
  12.   18: astore_1        
  13.   19: aload_1         
  14.   20: invokeinterface #7,  1            // InterfaceMethod java/sql/Connection.createStatement:()Ljava/sql/Statement;  
  15.   25: astore_2        
  16.   26goto          42  
  17.   29: astore_0        
  18.   30: aload_0         
  19.   31: invokevirtual #11                 // Method java/io/IOException.printStackTrace:()V  
  20.   34goto          42  
  21.   37: astore_0        
  22.   38: aload_0         
  23.   39: invokevirtual #12                 // Method java/sql/SQLException.printStackTrace:()V  
  24.   42return          
  25. Exception table:  
  26.    from    to  target type  
  27.        0    26    29   Class java/io/IOException  
  28.        0    26    37   Class java/sql/SQLException  


   
   switch那里生成的字节码不太明显看出来优化在哪里,这个很明显。首先,字节码长度变少 其次,从最后可以看出,target type都指向29行,两个catch会指向不同的行~ 

   2、用更包容性的类型检查来重新抛出异常 

   在方法的声明上,使用throws语句时,你可以指定更加详细的异常类型。 
   
  

Java代码  收藏代码
  1. static class FirstException extends Exception { }  
  2. static class SecondException extends Exception { }  
  3.   
  4. public void rethrowException(String exceptionName) throws Exception {  
  5.   try {  
  6.      if (exceptionName.equals("First")) {  
  7.          throw new FirstException();  
  8.      } else {  
  9.          throw new SecondException();  
  10.      }  
  11.   } catch (Exception e) {  
  12.    throw e;  
  13.   }  
  14.  }  



   这个例子,try块中只能抛出两种异常,但是因为catch里的类型是 Exception,在java SE7以前的版本中,在方法声明中throws 只能写Exception,但是在java SE7及以后的版本中,可以在throws后面写 FirstException和SecondException——编译器能判断出throw e语句抛出的异常一定来自try块,并且try块只能抛出FirstException和SecondException。 
  

Java代码  收藏代码
  1.     public static void reThrowException(String exceptionName)  
  2.         throws FirstException, SecondException{  
  3. try {  
  4.     if ("first".equals(exceptionName))  
  5.     throw new FirstException();  
  6.     else  
  7.     throw new SecondException();  
  8.     } catch (Exception e) {  
  9.     throw e;  
  10.     }  
  11.        }  
  12.     


   
    所以尽管catch里的异常类型是Exception,编译器仍然能够知道它是FirstException和 SecondException的实例。怎么样,编译器变得更智能了吧。 

    但是,如果在catch里对异常重新赋值了,在方法的throws后无法再向上面那样写成FirstException和SecondException了,而需要写成 Exception。 

    具体来说,在Java SE 7及以后版本中,当你在catch语句里声明了一个或多个异常类型,并且在catch块里重新抛出了这些异常,编译器根据下面几个条件来去核实异常的类型: 
     
- Try块里抛出它 
- 前面没有catch块处理它 
- 它是catch里一个异常类型的父类或子类。 


    特性6:创建泛型对象时类型推断 

    只要编译器可以从上下文中推断出类型参数,你就可以用一对空着的尖括号<>来代替泛型参数。这对括号私下被称为菱形(diamond)。 

    在Java SE 7之前,你声明泛型对象时要这样 
   

Java代码  收藏代码
  1. List<String> list = new ArrayList<String>();  



    而在Java SE7以后,你可以这样 
   

Java代码  收藏代码
  1. List<String> list = new ArrayList<>();  


   
     因为编译器可以从前面(List)推断出推断出类型参数,所以后面的ArrayList之后可以不用写泛型参数了,只用一对空着的尖括号就行。当然,你必须带着”菱形”<>,否则会有警告的。 
   
     Java SE7 只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可以使用类型推断,否则不行。 
    

Java代码  收藏代码
  1. List<String> list = new ArrayList<>();  
  2. list.add("A");  
  3.   
  4. //这个不行  
  5. list.addAll(new ArrayList<>());  
  6.   
  7. // 这个可以  
  8. List<? extends String> list2 = new ArrayList<>();  
  9. list.addAll(list2);  



     注意:菱形<>主要用在变量声明里。 
  
     类里也可以使用类型推断 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics