Java 8の新特性のラボンダの役割動力ノードJava学院の整理

5437 ワード

私たちは長い間Lambadaがjavaのために閉塞の概念を持ってくることを期待していますが、もし私たちが集合の中でそれを使わないと、大きな価値を失います。既存のインターフェースがlambadaスタイルに移行する問題はすでにdefault methodsによって解決されました。この文章ではJava集合の中の大量データ操作を深く解析し、lambar最強作用の神秘的なベールを解きます。
1.JSR 335について
JSRはJava Specification Requestsの略語であり、Java規格要求という意味であり、Java 8バージョンの主な改良はLambadaプロジェクト(JSR 335)であり、Javaをより多くの核プロセッサのためにコードを作成しやすくすることを目的としている。
2.外部VS内部反復
以前のJava集合は内部反復を表現することができず、外部反復の方式、すなわちforまたはwhileサイクルのみを提供していた。

List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));
for (Person p : persons) {
 p.setLastName("Doe");
}
上記の例は私達の以前のやり方で、いわゆる外部反復であり、循環は固定的な順序循環である。現在の多核時代において、並列循環を考えるなら、上記のコードを修正しなければなりません。効率がどれほど向上するかはもちろん、一定のリスク(スレッド安全問題など)をもたらす。 
内部反復を説明するには、Lambadaのようなクラスが必要です。次にlamdaとCollection.forEachを利用して上記のサイクルを書き換えます。 

persons.forEach(p->p.setLastName("Doe"));
今はjdkライブラリでサイクルをコントロールしていますが、どのように各personオブジェクトの中にセットされているのかについては心配しないでください。これは内部反復であり、クライアントは動作p.set LastNameをデータとしてapiに導入する。 内部反復は、実際には集合の大量操作と密接に関係していません。これによって文法的表現の変化を感じます。本当に面白いのは大量操作と関連があるのは新しいストリームAPIです。新しいjava.util.streamパッケージはJDK 8に追加されました。
3.Stream API
ストリーム(Stream)はデータストリームを表しているだけで、データ構造がないので、彼は一度の遍歴を経てから、もう遍歴できなくなります。(これはプログラミングする時に注意が必要です。Collectionと違って、何度も遍歴してもデータがあります。)、そのソースはCollection、array、ioなどです。
3.1中間と終点の方法
ストリームの役割は、データ操作をより容易かつ迅速にするために、大きなデータインターフェースを提供することである。フィルタリング、マッピング、パスの低減などの方法があります。これらの方法は中間方法と端末方法に分けられています。「ストリーム」の抽象は生まれつき持続的であり、中間方法は永遠にStreamに戻ります。したがって、最終結果を得るためにはエンドポイント操作を使ってストリームの最終結果を収集する必要があります。この二つの方法を区別するのは彼の戻り値を見ることです。Streamなら中間方法です。そうでなければ終点方法です。
いくつかの中間方法(filter、map)と終点方法(collect、sum)を簡単に紹介します。
3.1.1 Filter
データストリームでフィルタ機能を実現することは、まず考えられる最も自然な操作です。Streamインターフェースは、フィルタ条件を定義したlamband表現を使用して、動作を表すPrdicate実装を受け入れることができるfilter法を露出している。

List persons = …
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//  18     
3.1.2 Map
もし私たちが今データをフィルタリングしたら、例えば対象を変える時。Map操作により、Functionの実装(Function<T,R>の汎型Tを実行できます。Rは入力と実行結果をそれぞれ表します。まず、匿名の内部クラスでどう説明するかを見てみましょう。

Stream adult= persons
    .stream()
    .filter(p -> p.getAge() > 18)
    .map(new Function() {
     @Override
     public Adult apply(Person person) {
      return new Adult(person);//   18        
     }
    });
ここでは、上記の例をラダ式の書き方に変換します。

Stream map = persons.stream()
     .filter(p -> p.getAge() > 18)
     .map(person -> new Adult(person));
3.1.3 Count
count方法は流れの終点方法であり、流れの結果を最終的に集計して、intに戻すことができます。例えば18歳を満たす人数を計算します。

int countOfAdult=persons.stream()
      .filter(p -> p.getAge() > 18)
      .map(person -> new Adult(person))
      .count();
3.1.4 Collect
collect方法も一つの流れの終点方法であり、最終的な結果を収集することができます。

List adultList= persons.stream()
      .filter(p -> p.getAge() > 18)
      .map(person -> new Adult(person))
      .collect(Collectors.toList());
あるいは、特定の実装クラスを使って結果を収集したい場合:

List adultList = persons
     .stream()
     .filter(p -> p.getAge() > 18)
     .map(person -> new Adult(person))
     .collect(Collectors.toCollection(ArrayList::new));
紙幅は限られています。他の中間方法と終点方法は一つ一つ紹介しません。上のいくつかの例を見て、この二つの方法の違いが分かります。後は需要に応じて使うことができます。
3.2シーケンスストリームと並列ストリーム
各Streamには、順番実行と並行実行の2つのモードがあります。
シーケンスストリーム:

List <Person> people = list.getStream.collect(Collectors.toList());
並列ストリーム:

List <Person> people = list.getStream.parallel().collect(Collectors.toList());
名前の通りに、順番に繰り返して、各アイテムを読んでから次のアイテムを読みます。パラレルパスの使用により、配列は複数のセグメントに分割され、それぞれが異なるスレッドで処理され、結果を一緒に出力します。
3.2.1並列流の原理:

List originalList = someData;
split1 = originalList(0, mid);//       
split2 = originalList(mid,end);
new Runnable(split1.process());//       
new Runnable(split2.process());
List revisedList = split1 + split2;//     
みんなはhadoopについて少し知っています。中身はMapReduceです。 それ自体は、大データセットを並列処理するためのソフトウェアの枠組みであり、大データを処理する核心思想は大きく小さく、異なるマシンに割り当ててmapを実行し、最終的にはreduceによって、すべてのマシンの結果を結び付けて一つの最終結果を得ることができます。MapReduceとは違って、Streamは、多核技術を利用して、大きなデータをマルチコアによって並列処理することができます。MapReduceは分散できます。
3.2.2順序と並列性能テストの比較
多核マシンであれば、理論的に並行して流れると、順序より倍速くなります。以下はテストコードです。

long t0 = System.nanoTime();

  //       100    ,   2     ,toArray()     

  int a[]=IntStream.range(0, 1_000_000).filter(p -> p % 2==0).toArray();

  long t1 = System.nanoTime();

  //       ,          

  int b[]=IntStream.range(0, 1_000_000).parallel().filter(p -> p % 2==0).toArray();

  long t2 = System.nanoTime();

  //       serial: 0.06s, parallel 0.02s,            

  System.out.printf("serial: %.2fs, parallel %.2fs%n", (t1 - t0) * 1e-9, (t2 - t1) * 1e-9);
3.3 Folk/Joinフレームについて
アプリケーションハードウェアの並列性はjava 7にあります。java.util.co ncurrentパッケージの新規機能の一つはfork-joinスタイルのパラレル分解フレームであり、同じく強力で効率的で、興味のある学生が研究に行きます。
4.まとめ
もしlambandがないなら、Streamはかなり違和感があります。彼は上の3.1.2 mapのような匿名内部の多くの種類を生み出します。default methodがないと、集合フレームが変更されるのは必然的に多くの変更を引き起こします。だから、lamda+default methodはjdkライブラリをより強くし、柔軟にして、Streamと集合フレームの改善が一番いい証明です。