Java 8 新特征最終版指南詳解。本站提示廣大學習愛好者:(Java 8 新特征最終版指南詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Java 8 新特征最終版指南詳解正文
媒介: Java 8曾經頒布有一段時光了,各種跡象注解Java 8是一個有嚴重轉變的刊行版。在Java Code Geeks上曾經有許多引見Java 8新特征的文章,例如Playing with Java 8 – Lambdas and Concurrency、Java 8 Date Time API Tutorial : LocalDateTime和Abstract Class Versus Interface in the JDK 8 Era。本文還參考了一些其他材料,例如:15 Must Read Java 8 Tutorials和The Dark Side of Java 8。本文綜合了上述材料,整頓成一份關於Java 8新特征的參考教材,願望你有所收成。
1. 簡介
毫無疑問,Java 8是Java自Java 5(宣布於2004年)以後的最主要的版本。這個版本包括說話、編譯器、庫、對象和JVM等方面的十多個新特征。在本文中我們將進修這些新特征,並用現實的例子解釋在甚麼場景下合適應用。
這個教程包括Java開辟者常常面臨的幾類成績:
說話
編譯器
庫
對象
運轉時(JVM)
2. Java說話的新特征
Java 8是Java的一個嚴重版本,有人以為,固然這些新特征領Java開辟人員非常等待,但同時也須要花很多精神去進修。在這一末節中,我們將引見Java 8的年夜部門新特征。
2.1 Lambda表達式和函數式接口
Lambda表達式(也稱為閉包)是Java 8中最年夜和最使人等待的說話轉變。它許可我們將函數當做參數傳遞給某個辦法,或許把代碼自己看成數據處置:函數式開辟者異常熟習這些概念。許多JVM平台上的說話(Groovy、Scala等)從出生之日就支撐Lambda表達式,然則Java開辟者沒有選擇,只能應用匿名外部類取代Lambda表達式。
Lambda的設計消耗了許多時光和很年夜的社區力氣,終究找到一種折衷的完成計劃,可以完成簡練而緊湊的說話構造。最簡略的Lambda表達式可由逗號分隔的參數列表、->符號和語句塊構成,例如:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
在下面這個代碼中的參數e的類型是由編譯器推理得出的,你也能夠顯式指定該參數的類型,例如:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
假如Lambda表達式須要更龐雜的語句塊,則可使用花括號將該語句塊括起來,相似於Java中的函數體,例如:
Arrays.asList( "a", "b", "d" ).forEach( e -> { System.out.print( e ); System.out.print( e ); } );
Lambda表達式可以援用類成員和部分變量(會將這些變量隱式得轉換成final的),例以下列兩個代碼塊的後果完整雷同:
String separator = ","; Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.print( e + separator ) );
和
final String separator = ","; Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.print( e + separator ) );
Lambda表達式有前往值,前往值的類型也由編譯器推理得出。假如Lambda表達式中的語句塊只要一行,則可以不消應用return語句,以下兩個代碼片斷後果雷同:
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
和
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> { int result = e1.compareTo( e2 ); return result; } );
Lambda的設計者們為了讓現有的功效與Lambda表達式優越兼容,斟酌了許多辦法,因而發生了函數接口這個概念。函數接口指的是只要一個函數的接口,如許的接口可以隱式轉換為Lambda表達式。java.lang.Runnable和java.util.concurrent.Callable是函數式接口的最好例子。在理論中,函數式接口異常軟弱:只需某個開辟者在該接口中添加一個函數,則該接口就不再是函數式接口進而招致編譯掉敗。為了戰勝這類代碼層面的軟弱性,並顯式解釋某個接口是函數式接口,Java 8 供給了一個特別的注解@FunctionalInterface(Java 庫中的一切相干接口都曾經帶有這個注解了),舉個簡略的函數式接口的界說:
@FunctionalInterface public interface Functional { void method(); }
不外有一點須要留意,默許辦法和靜態辦法不會損壞函數式接口的界說,是以以下的代碼是正當的。
@FunctionalInterface public interface FunctionalDefaultMethods { void method(); default void defaultMethod() { } }
Lambda表達式作為Java 8的最年夜賣點,它有潛力吸引更多的開辟者參加到JVM平台,並在純Java編程中應用函數式編程的概念。假如你須要懂得更多Lambda表達式的細節,可以參考官方文檔。
2.2 接口的默許辦法和靜態辦法
Java 8應用兩個新概念擴大了接口的寄義:默許辦法和靜態辦法。默許辦法使得接口有點相似traits,不外要完成的目的紛歧樣。默許辦法使得開辟者可以在 不損壞二進制兼容性的條件下,往現存接口中添加新的辦法,即不強迫那些完成了該接口的類也同時完成這個新加的辦法。
默許辦法和籠統辦法之間的差別在於籠統辦法須要完成,而默許辦法不須要。接口供給的默許辦法會被接口的完成類繼續或許覆寫,例子代碼以下:
private interface Defaulable { // Interfaces now allow default methods, the implementer may or // may not implement (override) them. default String notRequired() { return "Default implementation"; } } private static class DefaultableImpl implements Defaulable { } private static class OverridableImpl implements Defaulable { @Override public String notRequired() { return "Overridden implementation"; } }
Defaulable接口應用症結字default界說了一個默許辦法notRequired()。DefaultableImpl類完成了這個接口,同時默許繼續了這個接口中的默許辦法;OverridableImpl類也完成了這個接口,但覆寫了該接口的默許辦法,並供給了一個分歧的完成。
Java 8帶來的另外一個風趣的特征是在接口中可以界說靜態辦法,例子代碼以下:
private interface DefaulableFactory { // Interfaces now allow static methods static Defaulable create( Supplier< Defaulable > supplier ) { return supplier.get(); } }
上面的代碼片斷整合了默許辦法和靜態辦法的應用場景:
public static void main( String[] args ) { Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new ); System.out.println( defaulable.notRequired() ); defaulable = DefaulableFactory.create( OverridableImpl::new ); System.out.println( defaulable.notRequired() ); }
這段代碼的輸入成果以下:
Default implementation
Overridden implementation
因為JVM上的默許辦法的完成在字節碼層面供給了支撐,是以效力異常高。默許辦法許可在不打破現有繼續系統的基本上改良接口。該特征在官方庫中的運用是:給java.util.Collection接口添加新辦法,如stream()、parallelStream()、forEach()和removeIf()等等。
雖然默許辦法有這麼多利益,但在現實開辟中應當謹嚴應用:在龐雜的繼續系統中,默許辦法能夠惹起歧義和編譯毛病。假如你想懂得更多細節,可以參考官方文檔。
2.3 辦法援用
辦法援用使得開辟者可以直接援用現存的辦法、Java類的結構辦法或許實例對象。辦法援用和Lambda表達式合營應用,使得java類的結構辦法看起來緊湊而簡練,沒有許多龐雜的模板代碼。
西門的例子中,Car類是分歧辦法援用的例子,可以贊助讀者辨別四品種型的辦法援用。
public static class Car { public static Car create( final Supplier< Car > supplier ) { return supplier.get(); } public static void collide( final Car car ) { System.out.println( "Collided " + car.toString() ); } public void follow( final Car another ) { System.out.println( "Following the " + another.toString() ); } public void repair() { System.out.println( "Repaired " + this.toString() ); } }
第一種辦法援用的類型是結構器援用,語法是Class::new,或許更普通的情勢:Class<T>::new。留意:這個結構器沒有參數。
final Car car = Car.create( Car::new ); final List< Car > cars = Arrays.asList( car );
第二種辦法援用的類型是靜態辦法援用,語法是Class::static_method。留意:這個辦法接收一個Car類型的參數。
cars.forEach( Car::collide );
第三種辦法援用的類型是某個類的成員辦法的援用,語法是Class::method,留意,這個辦法沒有界說入參:
cars.forEach( Car::repair );
第四種辦法援用的類型是某個實例對象的成員辦法的援用,語法是instance::method。留意:這個辦法接收一個Car類型的參數:
final Car police = Car.create( Car::new ); cars.forEach( police::follow );
運轉上述例子,可以在掌握台看到以下輸入(Car實例能夠分歧):
Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
假如想懂得和進修更具體的內容,可以參考官方文檔
2.4 反復注解
自從Java 5中引入注解以來,這個特征開端變得異常風行,並在各個框架和項目中被普遍應用。不外,注解有一個很年夜的限制是:在統一個處所不克不及屢次應用統一個注解。Java 8打破了這個限制,引入了反復注解的概念,許可在統一個處所屢次應用統一個注解。
在Java 8中應用@Repeatable注解界說反復注解,現實上,這其實不是說話層面的改良,而是編譯器做的一個trick,底層的技巧依然雷同。可以應用上面的代碼解釋:
package com.javacodegeeks.java8.repeatable.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class RepeatingAnnotations { @Target( ElementType.TYPE ) @Retention( RetentionPolicy.RUNTIME ) public @interface Filters { Filter[] value(); } @Target( ElementType.TYPE ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( Filters.class ) public @interface Filter { String value(); }; @Filter( "filter1" ) @Filter( "filter2" ) public interface Filterable { } public static void main(String[] args) { for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) { System.out.println( filter.value() ); } } }
正如我們所見,這裡的Filter類應用@Repeatable(Filters.class)注解潤飾,而Filters是寄存Filter注解的容器,編譯器盡可能對開辟者屏障這些細節。如許,Filterable接口可以用兩個Filter注解正文(這裡並沒有提就任何干於Filters的信息)。
別的,反射API供給了一個新的辦法:getAnnotationsByType(),可以前往某個類型的反復注解,例如
Filterable.class.getAnnoation(Filters.class)將前往兩個Filter實例,輸入到掌握台的內容以下所示:
filter1
filter2
假如你願望懂得更多內容,可以參考官方文檔。
2.5 更好的類型揣摸
Java 8編譯器在類型揣摸方面有很年夜的晉升,在許多場景下編譯器可以推導出某個參數的數據類型,從而使得代碼更加簡練。例子代碼以下:
package com.javacodegeeks.java8.type.inference; public class Value< T > { public static< T > T defaultValue() { return null; } public T getOrDefault( T value, T defaultValue ) { return ( value != null ) ? value : defaultValue; } }
以下代碼是Value<String>類型的運用:
package com.javacodegeeks.java8.type.inference; public class TypeInference { public static void main(String[] args) { final Value< String > value = new Value<>(); value.getOrDefault( "22", Value.defaultValue() ); } }
參數Value.defaultValue()的類型由編譯器推導得出,不須要顯式指明。在Java 7中這段代碼會有編譯毛病,除非應用Value.<String>defaultValue()。
2.6 拓寬注解的運用場景
Java 8拓寬了注解的運用場景。如今,注解簡直可使用在任何元素上:部分變量、接口類型、超類和接話柄現類,乃至可以用在函數的異常界說上。上面是一些例子:
package com.javacodegeeks.java8.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Collection; public class Annotations { @Retention( RetentionPolicy.RUNTIME ) @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } ) public @interface NonEmpty { } public static class Holder< @NonEmpty T > extends @NonEmpty Object { public void method() throws @NonEmpty Exception { } } @SuppressWarnings( "unused" ) public static void main(String[] args) { final Holder< String > holder = new @NonEmpty Holder< String >(); @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>(); } }
ElementType.TYPE_USER和ElementType.TYPE_PARAMETER是Java 8新增的兩個注解,用於描寫注解的應用場景。Java 語
言也做了對應的轉變,以辨認這些新增的注解。
3. Java編譯器的新特征
3.1 參數稱號
為了在運轉時取得Java法式中辦法的參數稱號,老一輩的Java法式員必需應用分歧辦法,例如Paranamer liberary。Java 8終究將這個特征標准化,在說話層面(應用反射API和Parameter.getName()辦法)和字節碼層面(應用新的javac編譯器和-parameters參數)供給支撐。
package com.javacodegeeks.java8.parameter.names; import java.lang.reflect.Method; import java.lang.reflect.Parameter; public class ParameterNames { public static void main(String[] args) throws Exception { Method method = ParameterNames.class.getMethod( "main", String[].class ); for( final Parameter parameter: method.getParameters() ) { System.out.println( "Parameter: " + parameter.getName() ); } } }
在Java 8中這個特征是默許封閉的,是以假如不帶-parameters參數編譯上述代碼並運轉,則會輸入以下成果:
Parameter: arg0
假如帶-parameters參數,則會輸入以下成果(准確的成果):
Parameter: args
假如你應用Maven停止項目治理,則可以在maven-compiler-plugin編譯器的設置裝備擺設項中設置裝備擺設-parameters參數:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerArgument>-parameters</compilerArgument> <source>1.8</source> <target>1.8</target> </configuration> </plugin>
4. Java官方庫的新特征
Java 8增長了許多新的對象類(date/time類),並擴大了現存的對象類,以支撐古代的並發編程、函數式編程等。
4.1 Optional
Java運用中最多見的bug就是空值異常。在Java 8之前,Google Guava引入了Optionals類來處理NullPointerException,從而防止源碼被各類null檢討淨化,以便開辟者寫出加倍整潔的代碼。Java 8也將Optional參加了官方庫。
Optional僅僅是一個輕易:寄存T類型的值或許null。它供給了一些有效的接口來防止顯式的null檢討,可以參考Java 8官方文檔懂得更多細節。
接上去看一點應用Optional的例子:能夠為空的值或許某個類型的值:
Optional< String > fullName = Optional.ofNullable( null ); System.out.println( "Full Name is set? " + fullName.isPresent() ); System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
假如Optional實例持有一個非空值,則isPresent()辦法前往true,不然前往false;orElseGet()辦法,Optional實例持有null,則可以接收一個lambda表達式生成的默許值;map()辦法可以將現有的Opetional實例的值轉換成新的值;orElse()辦法與orElseGet()辦法相似,然則在持有null的時刻前往傳入的默許值。
上述代碼的輸入成果以下:
Full Name is set? false Full Name: [none] Hey Stranger!
再看下另外一個簡略的例子:
Optional< String > firstName = Optional.of( "Tom" ); System.out.println( "First Name is set? " + firstName.isPresent() ); System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) ); System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) ); System.out.println();
這個例子的輸入是:
First Name is set? true First Name: Tom Hey Tom!
假如想懂得更多的細節,請參考官方文檔。
4.2 Streams
新增的Stream API(java.util.stream)將生成情況的函數式編程引入了Java庫中。這是今朝為止最年夜的一次對Java庫的完美,以便開辟者可以或許寫出加倍有用、加倍簡練和緊湊的代碼。
Steam API極年夜得簡化了聚集操作(前面我們會看到不止是聚集),起首看下這個叫Task的類:
public class Streams { private enum Status { OPEN, CLOSED }; private static final class Task { private final Status status; private final Integer points; Task( final Status status, final Integer points ) { this.status = status; this.points = points; } public Integer getPoints() { return points; } public Status getStatus() { return status; } @Override public String toString() { return String.format( "[%s, %d]", status, points ); } } }
Task類有一個分數(或偽龐雜度)的概念,別的還有兩種狀況:OPEN或許CLOSED。如今假定有一個task聚集:
final Collection< Task > tasks = Arrays.asList( new Task( Status.OPEN, 5 ), new Task( Status.OPEN, 13 ), new Task( Status.CLOSED, 8 ) );
起首看一個成績:在這個task聚集中一共有若干個OPEN狀況的點?在Java 8之前,要處理這個成績,則須要應用foreach輪回遍歷task聚集;然則在Java 8中可以應用steams處理:包含一系列元素的列表,而且支撐次序和並行處置。
// Calculate total points of all active tasks using sum() final long totalPointsOfOpenTasks = tasks .stream() .filter( task -> task.getStatus() == Status.OPEN ) .mapToInt( Task::getPoints ) .sum(); System.out.println( "Total points: " + totalPointsOfOpenTasks );
運轉這個辦法的掌握台輸入是:
Total points: 18
這裡有許多常識點值得說。起首,tasks聚集被轉換成steam表現;其次,在steam上的filter操作會過濾失落一切CLOSED的task;第三,mapToInt操作基於每一個task實例的Task::getPoints辦法將task流轉換成Integer聚集;最初,經由過程sum辦法盤算總和,得出最初的成果。
在進修下一個例子之前,還須要記住一些steams(點此更多細節)的常識點。Steam之上的操作可分為中央操作和早期操作。
中央操作會前往一個新的steam——履行一個中央操作(例如filter)其實不會履行現實的過濾操作,而是創立一個新的steam,並將原steam中相符前提的元素放入新創立的steam。
早期操作(例如forEach或許sum),會遍歷steam並得出成果或許附帶成果;在履行早期操作以後,steam處置線曾經處置終了,就不克不及應用了。在簡直一切情形下,早期操作都是連忙對steam停止遍歷。
steam的另外一個價值是發明性地支撐並行處置(parallel processing)。關於上述的tasks聚集,我們可以用上面的代碼盤算一切義務的點數之和:
// Calculate total points of all tasks final double totalPoints = tasks .stream() .parallel() .map( task -> task.getPoints() ) // or map( Task::getPoints ) .reduce( 0, Integer::sum ); System.out.println( "Total points (all tasks): " + totalPoints );
這裡我們應用parallel辦法並行處置一切的task,並應用reduce辦法盤算終究的成果。掌握台輸入以下:
Total points(all tasks): 26.0
關於一個聚集,常常須要依據某些前提對個中的元素分組。應用steam供給的API可以很快完成這類義務,代碼以下:
// Group tasks by their status final Map< Status, List< Task > > map = tasks .stream() .collect( Collectors.groupingBy( Task::getStatus ) ); System.out.println( map );
掌握台的輸入以下:
{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
最初一個關於tasks聚集的例子成績是:若何盤算聚集中每一個義務的點數在聚集中所占的比重,詳細處置的代碼以下:
// Calculate the weight of each tasks (as percent of total points) final Collection< String > result = tasks .stream() // Stream< String > .mapToInt( Task::getPoints ) // IntStream .asLongStream() // LongStream .mapToDouble( points -> points / totalPoints ) // DoubleStream .boxed() // Stream< Double > .mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream .mapToObj( percentage -> percentage + "%" ) // Stream< String> .collect( Collectors.toList() ); // List< String > System.out.println( result );
掌握台輸入成果以下:
[19%, 50%, 30%]
最初,正如之前所說,Steam API不只可以感化於Java聚集,傳統的IO操作(從文件或許收集一行一行得讀取數據)可以受害於steam處置,這裡有一個小例子:
final Path path = new File( filename ).toPath(); try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) { lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println ); }
Stream的辦法onClose 前往一個等價的有額定句柄的Stream,當Stream的close()辦法被挪用的時刻這個句柄會被履行。Stream API、Lambda表達式還有接口默許辦法和靜態辦法支撐的辦法援用,是Java 8對軟件開辟的古代范式的呼應。
4.3 Date/Time API(JSR 310)
Java 8引入了新的Date-Time API(JSR 310)來改良時光、日期的處置。時光和日期的治理一向是最令Java開辟者苦楚的成績。java.util.Date和後來的java.util.Calendar一向沒有處理這個成績(乃至令開辟者加倍渺茫)。
由於下面這些緣由,出生了第三方庫Joda-Time,可以替換Java的時光治理API。Java 8中新的時光和日期治理API深受Joda-Time影響,並接收了許多Joda-Time的精髓。新的java.time包包括了一切關於日期、時光、時區、Instant(跟日期相似然則准確到納秒)、duration(連續時光)和時鐘操作的類。新設計的API賣力斟酌了這些類的不變性(從java.util.Calendar汲取的經驗),假如某個實例須要修正,則前往一個新的對象。
我們接上去看看java.time包中的症結類和各自的應用例子。起首,Clock類應用時區來前往以後的納秒時光和日期。Clock可以替換System.currentTimeMillis()和TimeZone.getDefault()。
// Get the system clock as UTC offset final Clock clock = Clock.systemUTC(); System.out.println( clock.instant() ); System.out.println( clock.millis() );
這個例子的輸入成果是:
2014-04-12T15:19:29.282Z 1397315969360
第二,存眷下LocalDate和LocalTime類。LocalDate僅僅包括ISO-8601日歷體系中的日期部門;LocalTime則僅僅包括該日歷體系中的時光部門。這兩個類的對象都可使用Clock對象構建獲得。
// Get the local date and local time final LocalDate date = LocalDate.now(); final LocalDate dateFromClock = LocalDate.now( clock ); System.out.println( date ); System.out.println( dateFromClock ); // Get the local date and local time final LocalTime time = LocalTime.now(); final LocalTime timeFromClock = LocalTime.now( clock ); System.out.println( time ); System.out.println( timeFromClock );
上述例子的輸入成果以下:
2014-04-12 2014-04-12 11:25:54.568 15:25:54.568
LocalDateTime類包括了LocalDate和LocalTime的信息,然則不包括ISO-8601日歷體系中的時區信息。這裡有一些關於LocalDate和LocalTime的例子:
// Get the local date/time final LocalDateTime datetime = LocalDateTime.now(); final LocalDateTime datetimeFromClock = LocalDateTime.now( clock ); System.out.println( datetime ); System.out.println( datetimeFromClock );
上述這個例子的輸入成果以下:
2014-04-12T11:37:52.309 2014-04-12T15:37:52.309
假如你須要特准時區的data/time信息,則可使用ZoneDateTime,它保留有ISO-8601日期體系的日期和時光,並且有時區信息。上面是一些應用分歧時區的例子:
// Get the zoned date/time final ZonedDateTime zonedDatetime = ZonedDateTime.now(); final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock ); final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) ); System.out.println( zonedDatetime ); System.out.println( zonedDatetimeFromClock ); System.out.println( zonedDatetimeFromZone );
這個例子的輸入成果是:
2014-04-12T11:47:01.017-04:00[America/New_York] 2014-04-12T15:47:01.017Z 2014-04-12T08:47:01.017-07:00[America/Los_Angeles]
最初看下Duration類,它持有的時光准確到秒和納秒。這使得我們可以很輕易得盤算兩個日期之間的分歧,例子代碼以下:
// Get duration between two dates final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 ); final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 ); final Duration duration = Duration.between( from, to ); System.out.println( "Duration in days: " + duration.toDays() ); System.out.println( "Duration in hours: " + duration.toHours() );
這個例子用於盤算2014年4月16日和2015年4月16日之間的天數和小時數,輸入成果以下:
Duration in days: 365 Duration in hours: 8783
關於Java 8的新日期時光的整體印象照樣比擬積極的,一部門是由於Joda-Time的積極影響,另外一部門是由於官方終究聽取了開辟人員的需求。假如願望懂得更多細節,可以參考官方文檔。
4.4 Nashorn JavaScript引擎
Java 8供給了新的Nashorn JavaScript引擎,使得我們可以在JVM上開辟和運轉JS運用。Nashorn JavaScript引擎是javax.script.ScriptEngine的另外一個完成版本,這類Script引擎遵守雷同的規矩,許可Java和JavaScript交互應用,例子代碼以下:
ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName( "JavaScript" ); System.out.println( engine.getClass().getName() ); System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
這個代碼的輸入成果以下:
jdk.nashorn.api.scripting.NashornScriptEngine Result: 2
4.5 Base64
對Base64編碼的支撐曾經被參加到Java 8官方庫中,如許不須要應用第三方庫便可以停止Base64編碼,例子代碼以下:
package com.javacodegeeks.java8.base64; import java.nio.charset.StandardCharsets; import java.util.Base64; public class Base64s { public static void main(String[] args) { final String text = "Base64 finally in Java 8!"; final String encoded = Base64 .getEncoder() .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) ); System.out.println( encoded ); final String decoded = new String( Base64.getDecoder().decode( encoded ), StandardCharsets.UTF_8 ); System.out.println( decoded ); } }
這個例子的輸入成果以下:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
新的Base64API也支撐URL和MINE的編碼解碼。
(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDecoder())。
4.6 並行數組
Java8版本新增了許多新的辦法,用於支撐並行數組處置。最主要的辦法是parallelSort(),可以明顯加速多核機械上的數組排序。上面的例子論證了parallexXxx系列的辦法:
package com.javacodegeeks.java8.parallel.arrays; import java.util.Arrays; import java.util.concurrent.ThreadLocalRandom; public class ParallelArrays { public static void main( String[] args ) { long[] arrayOfLong = new long [ 20000 ]; Arrays.parallelSetAll( arrayOfLong, index -> ThreadLocalRandom.current().nextInt( 1000000 ) ); Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) ); System.out.println(); Arrays.parallelSort( arrayOfLong ); Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) ); System.out.println(); } }
上述這些代碼應用parallelSetAll()辦法生成20000個隨機數,然後應用parallelSort()辦法停止排序。這個法式會輸入亂序數組和排序數組的前10個元素。上述例子的代碼輸入的成果是:
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 Sorted: 39 220 263 268 325 607 655 678 723 793
4.7 並發性
基於新增的lambda表達式和steam特征,為Java 8中為java.util.concurrent.ConcurrentHashMap類添加了新的辦法來支撐聚焦操作;別的,也為java.util.concurrentForkJoinPool類添加了新的辦法來支撐通用線程池操作(更多內容可以參考我們的並發編程課程)。
Java 8還添加了新的java.util.concurrent.locks.StampedLock類,用於支撐基於容量的鎖——該鎖有三個模子用於支撐讀寫操作(可以把這個鎖當作是java.util.concurrent.locks.ReadWriteLock的替換者)。
在java.util.concurrent.atomic包中也新增了很多對象類,羅列以下:
DoubleAccumulator
DoubleAdder
LongAccumulator
LongAdder
5. 新的Java對象
Java 8供給了一些新的敕令行對象,這部門會講授一些對開辟者最有效的對象。
5.1 Nashorn引擎:jjs
jjs是一個基於尺度Nashorn引擎的敕令行對象,可以接收js源碼並履行。例如,我們寫一個func.js文件,內容以下:
function f() { return 1; }; print( f() + 1 );
可以在敕令行中履行這個敕令:jjs func.js,掌握台輸入成果是:
2
假如須要懂得細節,可以參考官方文檔。
5.2 類依附剖析器:jdeps
jdeps是一個相當棒的敕令行對象,它可以展現包層級和類層級的Java類依附關系,它以.class文件、目次或許Jar文件為輸出,然後會把依附關系輸入到掌握台。
我們可以應用jedps剖析下Spring Framework庫,為了讓成果少一點,僅僅剖析一個JAR文件:org.springframework.core-3.0.5.RELEASE.jar。
jdeps org.springframework.core-3.0.5.RELEASE.jar
這個敕令會輸入許多成果,我們僅看下個中的一部門:依附關系依照包分組,假如在classpath上找不到依附,則顯示”not found”.
org.springframework.core-3.0.5.RELEASE.jar -> C:/Program Files/Java/jdk1.8.0/jre/lib/rt.jar org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar) -> java.io -> java.lang -> java.lang.annotation -> java.lang.ref -> java.lang.reflect -> java.util -> java.util.concurrent -> org.apache.commons.logging not found -> org.springframework.asm not found -> org.springframework.asm.commons not found org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar) -> java.lang -> java.lang.annotation -> java.lang.reflect -> java.util
更多的細節可以參考官方文檔。
6. JVM的新特征
應用Metaspace(JEP 122)取代耐久代(PermGen space)。在JVM參數方面,應用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize取代本來的-XX:PermSize和-XX:MaxPermSize。
7. 結論
經由過程為開辟者供給許多可以或許進步臨盆力的特征,Java 8使得Java平台進步了一年夜步。如今還不太合適將Java 8運用在臨盆體系中,然則在以後的幾個月中Java 8的運用率必定會慢慢進步(PS:原文時光是2014年5月9日,如今在許多公司Java 8曾經成為主流,我司因為體量太年夜,如今也在一點點上Java 8,固然慢然則好歹在進級了)。作為開辟者,如今應當進修一些Java 8的常識,為進級做好預備。