Java 8新特性前瞻


快端午小長假了,要上線的項目差不多完結了,終於有時間可以坐下來寫篇博客了。

這是篇對我看到的java 8新特性的一些總結,也是自己學習過程的總結。

幾乎可以說java 8是目前為止,自2004年java 5發布以來的java世界中最大的事件了。它帶來了java語言層面上的諸多改變,主要包括下面一些方面:語法、編譯器、庫、工具和運行時。

一,語法層面:

1,Lambda表達式。

lambda表達式是一種可調用對象,它允許我們將函數作為函數參數傳入。諸如C++、Groovy、Scala都已經支持lambda表達式。lambda表達式的設計已經花費了許多時間和社區努力,它已經有了比較簡潔和緊湊的結構。它最簡單的形式如下:

1 Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
View Code

在這段代碼里面,它只包含了變量e和函數體以及箭頭運算符。e是ArrayList里面的String類型參數,被編譯器調用,通過forEach循環來獲取,並通過—>來調用函數體,將變量e打印出來。該段代碼的lambda完整格式如下:

1 Arrays.asList( "a", "b", "d" ).forEach( e -> {
2     System.out.print( e );
3     System.out.print( e );
4 } );
View Code

同時,lambda表達式也可以引用其它變量,但是該變量應該顯式地聲明為final,如下:

1 final String separator = ",";
2 Arrays.asList( "a", "b", "d" ).forEach( 
3     ( String e ) -> System.out.print( e + separator ) );
View Code

還有一個lambda表達式的例子,是list進行排序的,也借以表達lambda表達式可以有返回值的特性:

1 Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
2     int result = e1.compareTo( e2 );
3     return result;
4 } );
View Code

其實要是只是對list進行排序的話,上段代碼可以簡寫成這樣:

1 Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
View Code

java的設計原本就參考了C++的諸多特性,lambda表達式也是源於對C++的模仿,但java 8中的lambda相對於C++中的而言,已經簡化了很多,完整的C++的lambda表達式包括捕獲列表、參數列表、箭頭表達式、函數體以及尾置返回類型。有一個例子如下:

1 int size_t=100;
2 [size_t](const string src1, const string src1)—>{src1.size()<src2.size()};
View Code

2,Java的設計者們想了大量辦法以使業已存在的功能支持lambda表達式,功能函數的概念便是其中之一。

函數接口(Functional Interface)是只含有一個方法的接口,我們經常使用的Runnable和Callable接口(這兩個接口在多線程的環境下經常使用,兩者最明顯的區別就是Runnable無返回值,我們無法獲取該線程的運算狀態,而Callable則具有返回值,可以返回線程的運算結果。)便是最具代表性的例子。但是這兩個接口是非常脆弱的,因為當開發人員往接口的定義里面再次添加方法聲明時,已有實現該方法的類將不能夠再運行。通過使用java注解@FunctionalInterface將使得接口具備這種能力,代碼示例如下:

1 @FunctionalInterface
2 public interface Functional {
3     void method();
4 }
View Code

在java 8中已經使接口Runnable和Callable接口添加了該注解。與此同時,java 8中提供的default和static方法不會對@FunctionalInterface接口產生影響。

3,下面了解一下java中的默認和靜態方法。

學習語言最有效的方法之一就是學習優秀的代碼實例,下面的就是優秀實例的其中之一:

 1 public interface DefaulableFactory {
 2      // Interfaces now allow static methods
 3      static Defaulable create( Supplier< Defaulable > supplier ) {
 4           return supplier.get();
 5      }
 6   
 7       private interface Defaulable {
 8           // Interfaces now allow default methods, the implementer    may or 
 9          // may not implement (override) them.
10          default String notRequired() { 
11              return "Default implementation"; 
12          }        
13      }
14          
15      private static class DefaultableImpl implements Defaulable {
16      }
17     
18      private static class OverridableImpl implements Defaulable {
19          @Override
20          public String notRequired() {
21              return "Overridden implementation";
22          }
23      }
24  
25      public static void main( String[] args ) {
26          Defaulable defaulable = DefaulableFactory.create(  DefaultableImpl::new );
27          System.out.println( defaulable.notRequired() );
28          
29          defaulable = DefaulableFactory.create( OverridableImpl::new );
30          System.out.println( defaulable.notRequired() );
31      }
32  
33  }
View Code

默認方法在函數定義的返回類型前面添加關鍵字default,同時添加了實現了功能的函數體。接口中的default方法使得實現了該接口的類可以不必實現該方法,當然也可以對其進行重寫。

添加了默認方法的接口具有了java 5中抽象類所能夠提供的功能,使得所有使用抽象類的地方都可以用擁有了default方法的接口取代,因此,不免讓人遐想:抽象類在此之后還有存在的意義嗎?!

同時,也要注意一下靜態方法的參數及其使用。尤其是Supplier<Defaultable> supplier和DefaultableImp::new,這兩種表達方式對java開發人員而言,還是挺新穎的。

4,可重復注解。

在java 8以前,相同類型的注解只能聲明一次,例如在java開發的過程中,對某個方法重寫,只能聲明一次@override;在android構台過程中,對某個方法聲明目標api,只有聲明一次@targetapi。但是在java 8中,相同類型的注解卻可以聲明多次,示例代碼如下:

 1 public class RepeatingAnnotations {
 2     @Target( ElementType.TYPE )
 3     @Retention( RetentionPolicy.RUNTIME )
 4     public @interface Filters {
 5         Filter[] value();
 6     }
 7     
 8     @Target( ElementType.TYPE )
 9     @Retention( RetentionPolicy.RUNTIME )
10     @Repeatable( Filters.class )
11     public @interface Filter {
12         String value();
13     };
14     
15     @Filter( "filter1" )
16     @Filter( "filter2" )
17     public interface Filterable {        
18     }
19     
20     public static void main(String[] args) {
21         for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
22             System.out.println( filter.value() );
23         }
24     }
25 }
View Code

在main方法中,Fileterable接口通過反射機制來獲取自身定義的注解,然后打印出來。

二,編譯器新特性

1,參數名

長久以來java開發人員都在想盡各種辦法以達到在運行時獲取參數名字的目的,如今,java 8將此功能引入了java世界。

如下:

1 public class ParameterNames {
2     public static void main(String[] args) throws Exception {
3         Method method = ParameterNames.class.getMethod( "main", String[].class );
4         for( final Parameter parameter: method.getParameters() ) {
5             System.out.println( "Parameter: " + parameter.getName() );
6         }
7     }
8 }
View Code

通過反射機制獲取Parameter類,然后調用新增的方法getName來獲取名字。

三,庫新特性

1,Optional

 NullPointerException(NPE)是引起應用崩潰的最著名的原因,這個估計每個開發人員都曾遇到過無數次。Google Guova項目組曾將Optional作為NPE的解決方案,受它的啟發,java 8將Optional引入java庫進來。

Optional僅僅是一個泛型容器:它保存一個T值或者是null,而且提供了大量的方法來檢查null值。它的使用方式,正好有個例子:

1 Optional< String > fullName = Optional.ofNullable( null );//Optional.of( "Tom" );
2 System.out.println( "Full Name is set? " + fullName.isPresent() );        
3 System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); 
4 System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
View Code

第二行isPresent()表示Optional中保存的值是否為null;第三行orElseGet()表示如果為空將進行怎樣的操作;第四行map()和orElse()表示如果Optional中的值不為空,則進行map里面的操作,否則的話執行orElse里面的操作。

2,日期時間API

java中的日期和時間API一直為開發人員所詬病,緊隨Calendar之后的Date也沒有改變這種狀況。而開源java包Joda-Time卻為這種狀況進行了極大的改善,java -8中的日期與時間API則受到了Joda-Time極大的啟發,並充分把它吸納了進來。

java 8中的日期與時間API使用非常簡單,一段代碼就可以把它闡明,有一段代碼如下:

 1 // Get the system clock as UTC offset 
 2 final Clock clock = Clock.systemUTC();
 3 System.out.println( clock.instant() );
 4 System.out.println( clock.millis() );
 5 
 6 // Get the local date and local time
 7 final LocalDate date = LocalDate.now();
 8 final LocalDate dateFromClock = LocalDate.now( clock );
 9         
10 System.out.println( date );
11 System.out.println( dateFromClock );
12         
13 // Get the local date and local time
14 final LocalTime time = LocalTime.now();
15 final LocalTime timeFromClock = LocalTime.now( clock );
16         
17 System.out.println( time );
18 System.out.println( timeFromClock );
19 
20 // Get the local date/time
21 final LocalDateTime datetime = LocalDateTime.now();
22 final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
23         
24 System.out.println( datetime );
25 System.out.println( datetimeFromClock );
26 
27 // Get the zoned date/time
28 final ZonedDateTime zonedDatetime = ZonedDateTime.now();
29 final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
30 final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );
31         
32 System.out.println( zonedDatetime );
33 System.out.println( zonedDatetimeFromClock );
34 System.out.println( zonedDatetimeFromZone );
35 
36 // Get duration between two dates
37 final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
38 final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
39 
40 final Duration duration = Duration.between( from, to );
41 System.out.println( "Duration in days: " + duration.toDays() );
42 System.out.println( "Duration in hours: " + duration.toHours() );
View Code

3,Base64

終於,java把Base64加密/解密算法引入到最新版本中。使用如下:

 1 public class Base64s {
 2     public static void main(String[] args) {
 3         final String text = "Base64 finally in Java 8!";
 4         
 5         final String encoded = Base64
 6             .getEncoder()
 7             .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
 8         System.out.println( encoded );
 9         
10         final String decoded = new String( 
11             Base64.getDecoder().decode( encoded ),
12             StandardCharsets.UTF_8 );
13         System.out.println( decoded );
14     }
15 }
View Code

與此同時,java 8中的Base64也提供了對URL和MIME的加密/解密支持。(Base64.getUrlEncoder() / Base64.getUrlDecoder()Base64.getMimeEncoder() / Base64.getMimeDecoder())

4,並行數組

java 8提供了許多新的方法來支持對數組的並行處理,尤其是並行排序(parralelSort()),這種並行機制將充分利用處理品的多核機制,是對當前處理器發展趨勢的順應和完全把握。有個小例子如下:

 1 public class ParallelArrays {
 2     public static void main( String[] args ) {
 3         long[] arrayOfLong = new long [ 20000 ];        
 4         
 5         Arrays.parallelSetAll( arrayOfLong, 
 6             index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
 7         Arrays.stream( arrayOfLong ).limit( 10 ).forEach( 
 8             i -> System.out.print( i + " " ) );
 9         System.out.println();
10         
11         Arrays.parallelSort( arrayOfLong );        
12         Arrays.stream( arrayOfLong ).limit( 10 ).forEach( 
13             i -> System.out.print( i + " " ) );
14         System.out.println();
15     }
16 }
View Code

5,並發

並發常用的ConcurrentHashMap在java 8中改進了hash算法,降低了沖突的概率,當然,只是針對當鍵的類型為String的時候,其它類型鍵類型的沖突概率沒有變化。

同時變化的並發用的類還有:ForkJoinPool,StampedLock,ReadWriteLock。新增的類有:DoubleAccumulator,DoubleAdder,LongAccumulator和LongAdder。

四,工具

java 8中新增加了兩個工具,一個是js引擎工具(jjs),一個是類依存分析器(jdeps)。

例如一個js文件func.js,內容為function f(){return 1;}; print(f()+1);則在命令行中輸入jjs func.js,就會輸出2。

而對於jdeps工具,當輸入一個 .class,文件夾或者.jar文件時,就會輸出輸入內容的類之間的依賴關系。例如輸入:jdeps or.springframework.core-3.0.5.RELEASE.jar時,就會輸出如下內容:

 1 org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar
 2    org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)
 3       -> java.io                                            
 4       -> java.lang                                          
 5       -> java.lang.annotation                               
 6       -> java.lang.ref                                      
 7       -> java.lang.reflect                                  
 8       -> java.util                                          
 9       -> java.util.concurrent                               
10       -> org.apache.commons.logging                         not found
11       -> org.springframework.asm                            not found
12       -> org.springframework.asm.commons                    not found
13    org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)
14       -> java.lang                                          
15       -> java.lang.annotation                               
16       -> java.lang.reflect                                  
17       -> java.util
View Code

五,運行時(JVM)

在java 8中PermGen將不再存在,相反,Metaspace將會取代其位置。

JVM中-XX:PermSize和-XX:MaxPermSize將會被-XX:MetaSpaceSize和-XX:MaxMetaSpace取代。

 

總之,java 8的發布是java進化史上的一個重要的里程碑,java吸收了大量其它語言(尤其是c++)的優勢,java 8也是今年java界最為令人激動的一件事。

本文參考許多其它的文章,地址附錄如下,有興趣的同行可以看一下:

http://www.javacodegeeks.com/2014/05/java-8-features-tutorial.html ;

http://www.javacodegeeks.com/2014/04/abstract-class-versus-interface-in-the-jdk-8-era.html ;

http://openjdk.java.net/jeps/180 ;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM