序文: Java 8はしばらくリリースされており、すべての兆候は、Java 8が分布の大きな変化であることを示しています。 Java 8 Lambdasや並行性、Java 8 Date Time APIチュートリアル:JDK 8時代のインターフェースとインターフェイスなど、Java 8 Lambdasやconcurrencyなど、Java 8の新機能を導入するJavaコードオタクに関する記事がすでにたくさんあります。この記事では、次のような他の情報についても説明しています。15はJava 8チュートリアルとJava 8のダークサイドを読む必要があります。この記事は上記の情報をまとめて、Java 8の新機能に関する参照教科書にまとめました。
1。はじめに
Java 8がJava 5以来のJavaの最も重要なバージョンであることは間違いありません(2004年にリリース)。このバージョンには、言語、コンパイラ、ライブラリ、ツール、JVMに12を超える新機能が含まれています。この記事では、これらの新機能を学び、実用的な例を使用して、どのシナリオが使用に適しているかを説明します。
このチュートリアルには、Java開発者がしばしば直面するいくつかのタイプの問題が含まれています。
言語
コンパイラ
図書館
道具
ランタイム(JVM)
2。Java言語の新機能
Java 8はJavaのメジャーバージョンです。一部の人々は、これらの新機能はJava開発者によって期待されているが、学ぶために多くの努力が必要であると信じている人もいます。このセクションでは、Java 8の新機能のほとんどを紹介します。
2.1ラムダ式と機能的界面
Lambda式(閉鎖とも呼ばれる)は、Java 8の最大かつ最も予想される言語の変更です。これにより、関数をメソッドにパラメーターとして渡すか、データ自体をデータとして処理できます。機能開発者はこれらの概念に非常に精通しています。 JVMプラットフォームの多くの言語(Groovy、Scalaなど)は、生まれてからLambdaの表現をサポートしてきましたが、Java開発者は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式は、クラスメンバーとローカル変数(これらの変数を暗黙的に最終的に変換する)を参照できます。たとえば、次の2つのコードブロックにはまったく同じ効果があります。
string separator = "、"; arrays.aslist( "a"、 "b"、 "d")
そして
final string separator = "、"; arrays.aslist( "a"、 "b"、 "d")
Lambda式には戻り値があり、返品値のタイプもコンパイラの推論によって導出されます。 Lambda式のステートメントブロックに1つの行が1つしかない場合、returnステートメントを使用する必要はありません。次の2つのコードスニペットには同じ効果があります。
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式とよく互換性のあるものにするために、多くの方法を検討したため、関数インターフェイスの概念を思いつきました。関数インターフェイスは、1つの関数のみを持つインターフェイスを指し、そのようなインターフェイスはLambda式に暗黙的に変換できます。 java.lang.runnableおよびjava.util.concurrent.callableは、機能的インターフェイスの最良の例です。実際には、機能的なインターフェイスは非常に壊れやすいです。開発者がインターフェイスに関数を追加する限り、インターフェイスは機能的なインターフェイスではなく、コンピレーションの障害になります。このコードレベルの脆弱性を克服し、インターフェイスが機能的なインターフェイスであることを明示的に述べるために、Java 8は特別な注釈@FunctionalInterface(Javaライブラリのすべての関連インターフェイスにすでにこの注釈があります)を提供し、機能的なインターフェイスの簡単な定義を提供します。
@functionalinterfaceパブリックインターフェイスfunctional {void method();}ただし、注意すべきことの1つは、デフォルトの方法と静的方法が機能的インターフェイスの定義を破壊しないため、次のコードが合法であることです。
@functionalinterface public interface functionaldefaultmethods {void method();デフォルトのvoid defaultmethod(){}}Lambda Expressionsは、Java 8の最大のセールスポイントとして、JVMプラットフォームに参加し、純粋なJavaプログラミングで機能プログラミングの概念を使用するために、より多くの開発者を引き付ける可能性があります。 Lambdaの表現についてもっと知る必要がある場合は、公式のドキュメントを参照できます。
2.2インターフェイスのデフォルトおよび静的方法
Java 8は、2つの新しい概念を使用して、インターフェイスの意味を拡張します。デフォルトメソッドと静的メソッドです。デフォルトの方法により、インターフェイスが特性に少し似ていますが、達成すべき目標は異なります。デフォルトの方法により、開発者はバイナリの互換性を破ることなく、既存のインターフェイスに新しい方法を追加できます。つまり、インターフェイスを実装するクラスに、新しく追加されたメソッドを同時に実装することを強制されません。
デフォルトの方法と抽象的なメソッドの違いは、抽象的なメソッドを実装する必要があることですが、デフォルトのメソッドは実装していません。インターフェイスによって提供されるデフォルトのメソッドは、インターフェイス実装クラスによって継承または上書きされます。例コードは次のとおりです。
プライベートインターフェイスDefaulable {//インターフェイスはデフォルトのメソッドを許可するようになり、実装者はそれらを実装(オーバーライド)しない場合があります。デフォルトの文字列notRequired(){return "default endumentation"; }} private static class defaultableimpl defaulable {} private static class overridableimplは、defaulable {@override public string notrequired(){return "Overriddened expmortation";}}}Defoulableインターフェイスは、キーワードを使用してデフォルトを使用して、NotRequired()を定義します。デフォルトのIMPLクラスは、このインターフェイスを実装し、デフォルトでこのインターフェイスのデフォルトメソッドを継承します。 OverridableImplクラスはこのインターフェイスも実装しますが、インターフェイスのデフォルトメソッドをオーバーライドし、異なる実装を提供します。
Java 8が提起したもう1つの興味深い機能は、インターフェイスで静的な方法を定義できることです。例コードは次のとおりです。
プライベートインターフェイスDefaulableFactory {//インターフェイスは静的メソッドを許可します。次のコードスニペットでは、デフォルトメソッドの使用シナリオと静的メソッドを統合します。
public static void main(string [] args){defaulaible default = defaulableFactory.create(defaultableimpl :: new); system.out.println(defaultable.notrequired()); defaulaiable = defaulableFactory.create(overridableimpl :: new); out.out.out.out.nutln(} nutln(} nutln(} nedotln);このコードの出力は次のとおりです。
デフォルトの実装
オーバーライドされた実装
JVMでデフォルトメソッドを実装すると、バイトコードレベルでサポートが提供されるため、非常に効率的です。デフォルトの方法により、既存の継承システムを破ることなく、インターフェイスを改善できます。公式ライブラリでのこの機能の適用は次のとおりです。java.util.collectionインターフェイスに新しいメソッドを追加します。
デフォルトの方法には非常に多くの利点がありますが、実際の開発には注意して使用する必要があります。複雑な継承システムでは、デフォルトの方法は曖昧さと編集エラーを引き起こす可能性があります。詳細を知りたい場合は、公式ドキュメントを参照してください。
2.3メソッド参照
メソッド参照により、開発者は既存のメソッド、Javaクラスコンストラクター、またはインスタンスオブジェクトを直接参照できます。メソッド参照とラムダ式は、互いに組み合わせて使用され、Javaクラスのコンストラクターが複雑なテンプレートコードを多く使用せずにコンパクトで簡潔に見せます。
サイモンの例では、車のクラスはさまざまなメソッド参照の例であり、読者が4種類のメソッド参照を区別するのに役立ちます。
public static class car {public static car create(final supplier <car> supplier){return supplier.get();} public static void colleague(final car carge){system.out.println( "collided" + car.tostring();} public void follow(ファイナルカー){system.out.out.out( {system.out.println( "Repaired" + this.toString());}}最初の方法の参照のタイプはコンストラクターの参照です。Syntaxはクラス::新しい、またはより一般的なフォーム:クラス<t> :: newです。注:このコンストラクターにはパラメーターがありません。
ファイナルカーカー= car.create(car :: new);最終リスト<car> cars = arrays.aslist(car);
2番目の方法の参照のタイプは静的メソッド参照であり、構文はクラス:: static_methodです。注:この方法は、車の種類のパラメーターを受け入れます。
cars.foreach(car :: collide);
3番目の方法は、特定のクラスのメンバーメソッドへの参照であり、構文はクラス::メソッドです。この方法ではパラメーターを定義しないことに注意してください。
cars.foreach(car ::修理);
参照される4番目の方法は、インスタンスオブジェクトのメンバーメソッドへの参照であり、構文はインスタンス::メソッドです。注:この方法は、車の種類のパラメーターを受け入れます。
ファイナルカー警察= car.create(car :: new); cars.foreach(警察::フォロー);
上記の例を実行すると、コンソールに次の出力が表示されます(車のインスタンスは異なる場合があります)。
com.javacodegeeks.java8.method.references.methodreferences$car@7a81197d修理com.javacodegeeks.java8.method.references.methodreference$$$car@7a81197d com.javacodegeeks.java8.method.References.MethodReferences$car@7a81197d
より詳細なコンテンツを理解して学びたい場合は、公式ドキュメントを参照できます
2.4コメントを繰り返します
Java 5に注釈が導入されて以来、この機能は非常に人気があり、さまざまなフレームワークやプロジェクトで広く使用されています。ただし、注釈には大きな制限があります。同じアノテーションを同じ場所で複数回使用することはできません。 Java 8はこの制限を破り、繰り返される注釈の概念を導入し、同じ場所で同じ注釈を複数回使用できるようにします。
@repeatableアノテーションを使用してJava 8で繰り返し注釈を定義することは、実際には言語レベルの改善ではなく、コンパイラによるトリックであり、基礎となるテクノロジーは依然として同じです。次のコードを使用して説明できます。
パッケージcom.javacodegeeks.java8.repeatable.annotations; java.lang.annotation.ElementTypeをインポートします。 java.lang.annotation.Repeatableをインポートします。 java.lang.annotation.retentionをインポートします。 java.lang.annotation.retentionPolicyをインポートします。 java.lang.annotation.targetをインポートします。 public class Class RepeatingAnnotations {@target(elementType.type)@retention(retentionPolicy.runtime)public @interface filters {filter [] value();} @target(elementType.type)@retention(retentionPolicy.runtime)@Repeatable(Filters.class.class.class.class.class.class.clats. @filter( "filter1")@filter( "filter2")public interface filterable {} public static void main(string [] args){for(filter:filterable.class.getannotationsbytype(filter.class)){system.out.println(filter.value();}}}}}}}}ご覧のとおり、ここのフィルタークラスでは@Repeatable(Filters.Class)アノテーションを使用し、フィルターはフィルターアノテーションを保存するコンテナです。コンパイラは、これらの詳細を開発者からブロックしようとします。このようにして、フィルター可能なインターフェイスは2つのフィルターアノテーションで注釈を付けることができます(ここにはフィルターに関する情報は言及されていません)。
さらに、反射APIは新しい方法を提供します:getAnnotationsbyType()は、たとえば、特定のタイプの重複した注釈を返すことができます。
filterable.class.getannoation(filters.class)は2つのフィルターインスタンスを返し、コンソールへのコンテンツ出力は次のとおりです。
filter1
filter2
もっと知りたい場合は、公式のドキュメントを参照できます。
2.5より良いタイプの推論
Java 8コンパイラは、タイプの推論を大幅に改善しました。多くのシナリオでは、コンパイラが特定のパラメーターのデータ型を推定して、コードをより簡潔にすることができます。例コードは次のとおりです。
パッケージ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)?値:defaultValue;}}次のコードは、タイプ値<文字列>のアプリケーションです。
パッケージ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();}}パラメーター値のタイプ。DefaultValue()はコンパイラによって導出され、明示的に指定する必要はありません。 Java 7では、このコードには値がない限り、コンパイルエラーがあります。<string> defaultValue()が使用されます。
2.6注釈のアプリケーションシナリオを拡大します
Java 8は、注釈のアプリケーションシナリオを拡大します。これで、注釈は、ローカル変数、インターフェイスタイプ、スーパークラス、インターフェイスの実装クラス、さらには関数の例外定義でさえ、ほぼすべての要素で使用できます。ここにいくつかの例があります:
パッケージcom.javacodegeeks.java8.annotations; java.lang.annotation.ElementTypeをインポートします。 java.lang.annotation.retentionをインポートします。 java.lang.annotation.retentionPolicyをインポートします。 java.lang.annotation.targetをインポートします。 java.util.arraylistをインポートします。 java.util.collectionをインポートします。パブリッククラスのアノテーション{@retention(retentionPolicy.runtime)@target({elementType.type_use、elementType.type_parameter})public static class holder <@nonempty t> extends @nonempty Object {nonempty exply( @suppresswarnings( "unused")public static void main(string [] args){final holder <string> holder = new @nonempty Holder <String>(); @nonempty collection <@nonempty string>文字列= new arrayList <>(); }}ElementType.Type_UserおよびElementType.Type_Parameterは、Antationsの使用シナリオを説明するためにJava 8に追加された2つの新しい注釈です。 Java言語
Yanはまた、これらの新しく追加されたメモを識別するために対応する変更を加えました。
3。Javaコンパイラの新機能
3.1パラメーター名
実行時にJavaプログラムでメソッドのパラメーター名を取得するには、Javaプログラマーの古い世代は、Paranamer Liberaryなどのさまざまな方法を使用する必要があります。 Java 8は最後に、言語レベル(反射APIとparameter.getName()メソッドを使用)とバイトコードレベル(新しいJavacコンパイラと-Parametersパラメーターを使用)を使用して、この機能を正規化します。
パッケージcom.javacodegeeks.java8.parameter.names; java.lang.reflt.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では、この機能はデフォルトでオフになっているため、パラメーターパラメーターなしで上記のコードをコンパイルして実行すると、次の結果が出力されます。
パラメーター:arg0
-parametersパラメーターを使用する場合、次の結果は出力されます(正しい結果):
パラメーター:args
Mavenをプロジェクト管理に使用する場合、Maven-Compiler-Pluginコンパイラ構成アイテムで-Parametersパラメーターを構成できます。
<プラグイン> <groupid> org.apache.maven.plugins </groupid> <artifactid> maven-compiler-plugin </artifactid> <バージョン> 3.1 </version> <configuration> -parameters </compilerargument>
4。Java公式図書館の新機能
Java 8は、多くの新しいツールクラス(日付/時刻クラス)を追加し、既存のツールクラスを拡張して、最新の同時プログラミング、機能プログラミングなどをサポートしました。
4.1オプション
Javaアプリケーションで最も一般的なバグは、ヌル値の例外です。 Java 8の前に、Google GuavaはNullpointerexceptionを解決するためにオプションクラスを導入し、さまざまなヌルチェックによって汚染されているソースコードを回避して、開発者がクリーナーコードを書くことができます。 Java 8は、公式ライブラリにオプションを追加します。
オプションは簡単なことです。タイプTまたはnullの値を保存します。明示的なヌルチェックを避けるためのいくつかの便利なインターフェイスを提供し、詳細については公式のJava 8ドキュメントを参照できます。
次に、オプションを使用する例を見てみましょう。空の値または特定のタイプの値をご覧ください。
optional <string> fullname = optional.ofnullable(null); system.out.println( "フルネームはset?" + fullname.ispresent()); system.out.println( "full name:" + fullname.orelseget(() - > "[none]")); system.out.println(fullname.map(s-> "hey" + s + "!").orelse( "hey stranger!"));
オプションのインスタンスが非ヌル値を保持している場合、ispresent()メソッドはtrueを返します。 orelseget()メソッド、およびオプションのインスタンスはnullを保持し、ラムダ式によって生成されたデフォルト値を受け入れることができます。 MAP()メソッドは、既存のオプションインスタンスの値を新しい値に変換できます。 orelse()メソッドはorelseget()メソッドに似ていますが、nullを保持するときに渡されたデフォルト値を返します。
上記のコードの出力結果は次のとおりです。
フルネームは設定されていますか?偽のフルネーム:[なし]ちょっと見知らぬ!
別の簡単な例を見てみましょう。
optional <string> firstName = optional.of( "tom"); system.out.println( "名は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();
この例の出力は次のとおりです。
名は設定されていますか?本当の名:トム・ヘイ・トム!
詳細を知りたい場合は、公式ドキュメントを参照してください。
4.2ストリーム
新しく追加されたストリームAPI(java.util.stream)は、生成された環境の機能的プログラミングをJavaライブラリに導入します。これは、開発者がより効率的で簡潔でコンパクトなコードを作成できるように、Javaライブラリの最大の改善です。
Steam APIは、コレクション操作を大幅に簡素化します(後でコレクション以上のものが表示されます)。まず、タスクと呼ばれるこのクラスを見てみましょう。
パブリッククラスストリーム{private enum status {open、closht};プライベート静的最終クラスタスク{プライベート最終ステータスステータス。プライベート最終整数ポイント;タスク(最終ステータス、最終整数ポイント){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);}}}}}}}タスククラスには、分数(または擬似複雑度)の概念があり、他にも2つの状態があります。オープンまたはクローズ。次に、タスクコレクションがあるとします。
最終的なコレクション<タスク> tasks = arrays.aslist(new Task(status.open、5)、new task(status.open、13)、new Task(status.closed、8));
まず、質問を見てみましょう。このタスクコレクションには、オープンステートポイントがいくつありますか? Java 8の前に、この問題を解決するには、タスクコレクションをループするためにEachを使用する必要があります。ただし、Java 8では、蒸気を使用して解決できます。一連の要素のリストを含め、順次処理と並列処理をサポートします。
// sum()final long totalpointsofopentasks = tasks.stream()。filter(task-> task.getstatus()== status.open).maptoint(task :: getpoints).sum(); sum.out.println( " + totalpointsofopentasksks);
この方法を実行するためのコンソール出力は次のとおりです。
合計ポイント:18
ここで話す価値のある多くの知識ポイントがあります。最初に、タスクセットは蒸気表現に変換されます。第二に、蒸気のフィルター操作は、すべての閉じたタスクをフィルタリングします。第三に、Maptoint操作は、タスクに基づいてタスクストリームを整数コレクションに変換します::各タスクインスタンスのメソッドメソッド。最後に、最終結果を取得するために合計が合計メソッドによって計算されます。
次の例を学ぶ前に、蒸気に関するいくつかの知識ポイントを覚えておく必要があります(詳細については、ここをクリックしてください)。蒸気を超える操作は、中間操作と後期操作に分けることができます。
中間操作は新しい蒸気を返します - 中間操作(フィルターなど)を実行すると、実際のフィルタリング操作は実行されませんが、新しい蒸気を作成し、元の蒸気の条件を満たす要素を新しく作成した蒸気に配置します。
遅い操作(foreachまたはsumなど)は、蒸気を横断し、結果またはそれに付随する結果を得ます。遅い操作を実行した後、蒸気処理ラインは処理されており、使用できません。ほとんどすべての場合、遅い操作はすぐに蒸気を横断しています。
蒸気のもう1つの価値は、並列処理に対する創造的なサポートです。上記のタスクコレクションでは、次のコードを使用して、すべてのタスクのポイントの合計を計算できます。
//すべてのタスクの合計ポイントを計算する最終的なダブルトータルポイント= tasks.stream()。parallem()。map(task-> task.getpoints())//またはmap(task :: getpoints).reduce(0、integer :: sum); system.out.println( "(すべてのタスク):" +合計ポイント);
ここでは、並列メソッドを使用して、すべてのタスクを並行して処理し、Reduceメソッドを使用して最終結果を計算します。コンソール出力は次のとおりです。
合計ポイント(すべてのタスク):26.0
コレクションの場合、特定の条件に応じて要素をグループ化する必要があることがよくあります。このタイプのタスクは、Steamによって提供されるAPIを使用して迅速に完了できます。コードは次のとおりです。
//ステータスによるグループタスク最終マップ<ステータス、リスト<タスク>>マップ= tasks.stream()。collect(collectors.groupingby(task :: getstatus)); system.out.println(map);
コンソールの出力は次のとおりです。
{閉じた= [[閉じ、8]]、open = [[open、5]、[open、13]]}
タスクコレクションに関する最後の例の質問は、コレクション内の各タスクのポイントの割合を計算する方法です。特定の処理コードは次のとおりです。
//各タスクの重量(合計ポイントのパーセント)最終収集<String> result = tasks.Stream()// stream <string> .maptoint(task :: getpoints)// intstream .aslongStream()// longstream .maptodouble(ポイント - >ポイント /ポイント /トータルポイント) )// longstream .maptoobj(パーセンテージ - >パーセンテージ + "%")// stream <string> .collect(collectors.tolist()); //リスト<String> System.out.println(result);
コンソール出力の結果は次のとおりです。
[19%、50%、30%]
最後に、前述のように、Steam APIはJavaコレクションだけでなく、従来のIO操作(ファイルまたはネットワークラインからのデータを読む)が蒸気処理の恩恵を受けることができます。ここに小さな例があります:
最終パスパス= new file(filename).topath(); try(Stream <String> lines = files.lines(path、stardingcharsets.utf_8)){lines.onclose(() - > system.out.println( "don!")).foreach(system.out :: println);}ストリームメソッドonCloseは、追加のハンドルで同等のストリームを返します。このハンドルは、ストリームのclose()メソッドが呼び出されると実行されます。インターフェイスのデフォルトメソッドと静的メソッドによってサポートされるストリームAPI、ラムダ式、およびメソッド参照は、ソフトウェア開発の最新のパラダイムに対するJava 8の応答です。
4.3日付/時刻API(JSR 310)
Java 8は、新しい日付API(JSR 310)を導入して、時間と日付の処理を改善します。日時と日付の管理は、Java開発者にとって常に最も苦痛な問題でした。 Java.util.dateおよびその後のJava.util.calendarは、この問題を解決していません(開発者にさらに混乱しています)。
上記の理由により、サードパーティの図書館Joda-Timeが生まれ、Javaの時間管理APIに取って代わることができます。 Java 8の新しい時間と日付の管理APIは、Joda-Timeの影響を深く受けており、Joda-Timeの多くの本質を吸収しています。新しいJava.timeパッケージには、日付、時刻、タイムゾーン、インスタント(日付と同様ですが、ナノ秒と正確な)、期間(期間)、およびクロック操作に関するすべてのクラスが含まれています。新しく設計されたAPIは、これらのクラスの不変性(java.util.calendarから学んだ講義)を真剣に検討し、インスタンスを変更する必要がある場合は新しいオブジェクトを返します。
Java.Timeパッケージの重要なクラスとそれぞれの使用例を見てみましょう。まず、クロッククラスはタイムゾーンを使用して、現在のナノ秒時間と日付を返します。クロックは、system.currenttimemillis()およびtimezone.getDefault()を置き換えることができます。
// utc 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には、カレンダーシステムの時間部分のみが含まれています。両方のクラスのオブジェクトは、時計オブジェクトを使用して構築できます。
//ローカル日付と現地時間を取得します最終localdate date = localdate.now(); final localdate date fromclock = localdate.now(clock); system.out.println(datefromclock); //ローカルの日付と現地時間を取得する最終localtime time = localtime.now(); final localtime timefrock = 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の例をいくつか紹介します。
// local date/time final localDateTime DateTime = localDateTime.now()を取得します。最終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
特定のタイムゾーンのデータ/時間情報が必要な場合は、ISO-8601日付システムの日付と時刻を保持し、タイムゾーン情報を持っているZonedateTimeを使用できます。異なるタイムゾーンを使用する例は次のとおりです。
//ゾーン日付/時刻最終zoneddatime zoneddateTime = zoneddateTime.now()を取得します。最終zoneddatime zoneddateTimefromclock = zoneddateTime.now(clock); final zoneddatime zoneddateTimefromzone = zoneddateTime.now(zoneid.of( "America/los_angeles")); System.out.println(zoneddateTime); system.out.println(zoneddateTimefromclock); 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 [アメリカ/ロスペンゲレス]
最後に、時間とナノ秒を保持する期間クラスを見てみましょう。これにより、2つの日付間の違いを簡単に計算できます。例のコードは次のとおりです。
// 2つの日付の間に最終localDateTimeから= localdateTime.of(2014年、月、16、0、0、0);最終localDateTime to = localdateTime.of(2015年、月。 duration.todays()); system.out.println( "時間の持続時間:" + duration.tohours());
この例は、2014年4月16日から2015年4月16日までの日数と時間数を計算するために使用され、出力は次のとおりです。
日数の期間:時間の365期間:8783
Java 8の新しい日付と時刻の全体的な印象は、Joda-Timeのプラスの影響のために、そして一部には、公式が最終的に開発者のニーズに耳を傾けたためです。詳細を知りたい場合は、公式ドキュメントを参照できます。
4.4ナショーンJavaScriptエンジン
Java 8は、新しいNashorn JavaScriptエンジンを提供し、JVMでJSアプリケーションを開発および実行できます。 Nashorn JavaScriptエンジンは、javax.script.scriptengineの別の実装バージョンです。このタイプのスクリプトエンジンは同じルールに従い、JavaとJavaScriptをインタラクティブに使用できるようにします。例コードは次のとおりです。
ScriptEngineManager Manager = new ScriptEngineManager(); ScriptEngine Engine = Manager.GetEngineByName( "JavaScript"); system.out.println(Engine.getClass()。getName()); out.println( "result:" + engine.eval( "function f(){return 1; f ^}; f ^};" + 1; ");このコードの出力は次のとおりです。
jdk.nashorn.api.scripting.nashornscriptengine結果:2
4.5 Base64
Base64エンコードのサポートは公式Java 8ライブラリに追加されているため、Shird Partyライブラリを使用せずにBase64エンコードを実行できます。例コードは次のとおりです。
パッケージcom.javacodegeeks.java8.base64; java.nio.charset.standardcharsetsをインポートします。 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(stardingcharsets.utf_8)); system.out.println(encoded); final string decoded = new String(base64.getDecoder()。デコード(エンコード)、StandardCharsets.utf_8); system.out.println(decoded);}}}この例の出力は次のとおりです。
qmfzzty0igzpbmfsbhkgaw4gsmf2ysa4iq ==
base64ついにJava 8!
新しいBase64APIは、URLと鉱山のエンコードとデコードもサポートしています。
(base64.geturlencoder() / base64.geturldecoder()、base64.getmimeencoder() / base64.getmimedecoder())。
4.6平行配列
Java8バージョンは、並列配列処理をサポートするための多くの新しい方法を追加しました。最も重要な方法は、マルチコアマシンでの配列ソートを大幅に高速化できるParallelsort()です。次の例は、ParallelExxxxシリーズの方法を示しています。
パッケージ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.jarorg.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 foundorg.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的知识,为升级做好准备。