
かなり前にJava 8がリリースされたという事実にもかかわらず、すべてのプログラマーがその新機能を使用するわけではありません。誰かがAndroidプロジェクトを行っており、ラムダとStream Apiの実装にサードパーティのライブラリを使用したくない、または使用できない。 ただし、インタビューではJavaプログラマーのラムダとStream Apiの知識が必要になることがよくあり、Java 8が使用されているプロジェクトに切り替えるときに役立つだけです。 ラムダと関数型プログラミングの知識は必要ありません(すべてを明確にするために例を示しました)。これは、Javaの最も基本的な知識以上のレベルです。
また、これはチートシートであるため、この記事を使用して、Java Stream Apiの特定の機能がどのように機能するかをすばやく覚えることができます。 主な機能の機能の簡単なリストは、記事の冒頭に記載されています。
Stream Apiが何なのかわからない人のためにストリームAPIは、機能的なスタイルでデータ構造を操作するための新しい方法です。 ほとんどの場合、Java 8のストリームを使用してコレクションを操作しますが、実際にはこのメカニズムはさまざまなデータに使用できます。
Stream Apiを使用すると、コレクションからすべての奇数の合計を取得するタスクが次のコードによって解決される前に、SQLのスタイルでデータ構造の処理を記述できます。
Integer sumOddOld = 0; for(Integer i: collection) { if(i % 2 != 0) { sumOddOld += i; } }
次に、Stream Apiを使用して、機能的なスタイルでこの問題を解決できます。
Integer sumOdd = collection.stream().filter(o -> o % 2 != 0).reduce((s1, s2) -> s1 + s2).orElse(0);
さらに、Stream Apiを使用すると、追加のコードなしでstream()をparallelStream()に変更するだけで問題を並列に解決できます
Integer sumOdd = collection.parallelStream().filter(o -> o % 2 != 0).reduce((s1, s2) -> s1 + s2).orElse(0);
セマフォ、同期、デッドロックのリスクなどなく、すでにコードを並列化します。
Java 8でストリームオブジェクトを作成することから始めましょう。
I.ストリームを作成する方法
ストリームを作成するいくつかの方法を次に示します。
ストリームを作成する方法 | 作成テンプレート | 例 |
---|
1.クラシック:コレクションからストリームを作成する | コレクション。 ストリーム () | Collection<String> collection = Arrays.asList("a1", "a2", "a3"); Stream<String> streamFromCollection = collection.stream(); |
2.値のストリームを作成する | Stream.of ( value1 、... valueN ) | Stream<String> streamFromValues = Stream.of("a1", "a2", "a3"); |
3.配列からストリームを作成する | Arrays.stream ( 配列 ) | String[] array = {"a1","a2","a3"}; Stream<String> streamFromArrays = Arrays.stream(array); |
4.ファイルからストリームを作成します(ファイルの各行は、ストリームの個別の要素になります) | Files.lines ( ファイルへのパス ) | Stream<String> streamFromFiles = Files.lines(Paths.get("file.txt")) |
5.文字列からストリームを作成する | 「ストリング」。 文字 () | IntStream streamFromString = "123".chars() |
6. Stream.builderを使用する | ストリーム ビルダー ()。 追加 (...).... ビルド () | Stream.builder().add("a1").add("a2").add("a3").build() |
7.並列ストリームの作成 | コレクション。 parallelStream () | Stream<String> stream = collection.parallelStream();
|
8. Stream.iterateを使用して無限のストリームを作成する
| Stream.iterate ( start_condition、generation_expression ) | Stream<Integer> streamFromIterate = Stream.iterate(1, n -> n + 1) |
9. Stream.generateを使用して無限ストリームを作成します | Stream.generate ( generation_expression ) | Stream<String> streamFromGenerate = Stream.generate(() -> "a1") |
原則として、ストリームを作成する最後の2つの方法に加えて、すべてがコレクションを作成する通常の方法と変わりません。 最後の2つのメソッドは、無限のストリームを生成するために機能します。初期条件が設定され、前の値から次の値を受け取る式、つまりStream.iterate(1、n-> n + 1)は値1、2、3、4、... Nを返しますStream.generateは定数値とランダム値を生成します。式に対応する値を返すだけです。この例では、無数の「a1」値を生成します。
ラムダを知らない人のために式n-> n + 1は、式Integer func(Integer n){return n + 1;}の単なる類似物であり、式()-> "a1"は、式String func(){return "a1";}の類似物です。匿名クラス。
より詳細な例また、この例は
github 'eにあります。
System.out.println("Test buildStream start");
II。 ストリーミング方法
Java Stream APIは、2種類のメソッドを提供します。
1.パイプライン-別のストリームを返します。つまり、ビルダーとして機能し、
2.ターミナル-コレクション、プリミティブ、オブジェクト、オプションなどの別のオブジェクトを返します。
パイプラインとターミナルメソッドの違い一般的なルール :ストリームには任意の数のパイプラインコールと最後に1つのターミナルを含めることができますが、すべてのパイプラインメソッドは遅延して実行され、ターミナルメソッドが呼び出されるまで、スレッドまたはRunnableオブジェクトを作成するように実際にアクションは発生しませんただし、startを呼び出さないでください。
一般に、このメカニズムはSQLクエリの構築に似ており、ネストされたSelectはいくつあってもかまいませんが、結果は1つだけです。 たとえば、式collection.stream()。Filter((s)-> s.contains( "1"))。Skip(2).findFirst()、filterおよびskipはパイプライン処理され、findFirstはターミナルであり、オブジェクトを返します。オプションで、これでストリームの操作が終了します。
2.1ストリームを操作するためのパイプライン化されたメソッドの簡単な説明
ストリーム方式 | 説明 | 例 |
---|
フィルター | レコードをフィルタリングし、条件に一致するレコードのみを返します | collection.stream()。filter( "a1" ::等しい).count() |
飛ばす | N個の最初の要素をスキップできます | collection.stream()。skip(collection.size()-1).findFirst()。orElse( "1") |
明確な | 重複のないストリームを返します(equalsメソッドの場合) | collection.stream()。distinct()。collect(Collectors.toList()) |
地図 | 各ストリーム項目を変換します | collection.stream()。map((s)-> s + "_1")。collect(Collectors.toList()) |
のぞく | 同じストリームを返しますが、ストリームの各要素に関数を適用します | collection.stream()。map(String :: toUpperCase).peek((e)-> System.out.print( "、" + e))。 collect(Collectors.toList()) |
限界 | 選択を特定の数の最初の要素に制限できます。 | collection.stream()。limit(2).collect(Collectors.toList()) |
ソート済み | 自然な順序で、またはComparatorを設定して、値を並べ替えることができます | collection.stream()。sort()。collect(Collectors.toList()) |
mapToInt 、 mapToDouble 、 mapToLong | mapに類似していますが、数値ストリーム(つまり、数値プリミティブのストリーム)を返します | collection.stream()。mapToInt((s)-> Integer.parseInt(s))。toArray() |
flatMap 、 flatMapToInt 、 flatMapToDouble 、 flatMapToLong | mapに似ていますが、1つの要素から複数を作成できます | collection.stream()。flatMap((p)-> Arrays.asList(p.split( "、"))。stream())。toArray(String [] :: new) |
2.2ストリームを操作する端末方法の簡単な説明
ストリーム方式 | 説明 | 例 |
---|
findFirst | ストリームの最初の要素を返します(オプションを返します) | collection.stream()。findFirst()。orElse( "1") |
findAny | ストリームから適切なアイテムを返します(オプションを返します) | collection.stream()。findAny()。orElse( "1") |
集める | コレクションおよびその他のデータ構造の形式での結果の表示 | collection.stream()。filter((s)-> s.contains( "1"))。collect(Collectors.toList()) |
数える | ストリーム内の要素の数を返します | collection.stream()。filter( "a1" ::等しい).count() |
anyMatch | 少なくとも1つの要素について条件が満たされる場合、trueを返します | collection.stream()。anyMatch( "a1" ::等しい) |
なし一致 | いずれかの要素について条件が満たされない場合、trueを返します | collection.stream()。noneMatch( "a8" ::等しい) |
allMatch | すべての要素について条件が真の場合、真を返します | collection.stream()。allMatch((s)-> s.contains( "1")) |
分 | コンパレーターを条件として使用して、最小要素を返します | collection.stream()。min(String :: compareTo).get() |
最大 | コンパレーターを条件として使用して、最大要素を返します | collection.stream()。max(String :: compareTo).get() |
forEach | 各ストリームオブジェクトに関数を適用します;並列実行での順序は保証されません | set.stream()。forEach((p)-> p.append( "_ 1")); |
forEachOrdered | 各ストリームオブジェクトに関数を適用します;要素の順序を保持すると、 | list.stream()。forEachOrdered((p)-> p.append( "_ new")); |
toArray | ストリーム値の配列を返します | collection.stream()。map(String :: toUpperCase).toArray(String [] :: new); |
減らす | コレクション全体で集計関数を実行し、単一の結果を返すことができます | collection.stream()。reduce((s1、s2)-> s1 + s2).orElse(0) |
メソッドfindFirst、findAny、anyMatchは短絡メソッドに注意してください。つまり、ストリームのバイパスは、元のストリーム全体をバイパスせずに、適切な要素をできるだけ早く見つけるように編成されます。
2.3数値ストリームの追加メソッドの簡単な説明
ストリーム方式 | 説明 | 例 |
---|
合計 | すべての数値の合計を返します | collection.stream()。mapToInt((s)-> Integer.parseInt(s))。sum() |
平均的 | すべての数値の算術平均を返します | collection.stream()。mapToInt((s)-> Integer.parseInt(s))。average() |
mapToObj | 数値ストリームをオブジェクトストリームに変換します | intStream.mapToObj((id)->新しいキー(id))。toArray() |
2.4他のいくつかの便利なストリームメソッド
ストリーム方式 | 説明 |
---|
isParallel | ストリームが並列かどうかを調べる |
平行 | 並列ストリームを返します。ストリームが既に並列である場合、それ自体を返すことができます |
シーケンシャル | 順次ストリームを返します。ストリームが既にシリアルである場合、それ自体を返すことができます |
並列および順次メソッドを使用して、どの操作が並列になり、どの操作が順次のみになるかを判別できます。 また、シーケンシャルストリームからパラレルストリームを作成することもできます。
collection.stream(). peek(...).
注 :すべての並列ストリームは1つのフォーク/結合プールで動作し、そのような長い操作はJVMのすべての並列ストリームの動作を停止する可能性があるため、長時間の操作(データベース、ネットワーク接続からのデータの取得)に並列ストリームを使用しないことを強くお勧めしますプールに利用可能なスレッドがないため、つまり 並列ストリームは、ミリ秒単位でカウントが行われる短い操作にのみ使用する必要がありますが、秒単位および分単位でカウントが可能な操作には使用しないでください。
III。 ストリームメソッドの使用例
コレクションを操作するときに通常必要なさまざまなタスクのメソッドを操作することを検討してください。
3.1 filter、findFirst、findAny、skip、limit、countの使用例
条件 :Arrays.asList文字列のコレクション(「a1」、「a2」、「a3」、「a1」)が与えられた場合、filter、findFirst、findAny、skip、countメソッドを使用してどのように処理できるかを見てみましょう。
挑戦する | サンプルコード | 結果 |
---|
オブジェクト「a1」の出現回数を返します | collection.stream()。filter( "a1" ::等しい).count() | 2 |
コレクションの最初の要素を返すか、コレクションが空の場合は0を返します | collection.stream()。findFirst()。orElse( "0") | a1 |
コレクションの最後のアイテムを返すか、コレクションが空の場合は「空」を返します | collection.stream()。skip(collection.size()-1).findAny()。orElse( "empty") | a1 |
「a3」に等しいコレクション内のアイテムを見つけるか、エラーをスローします | collection.stream()。filter( "a3" :: equals).findFirst()。get() | a3 |
コレクション内の3番目のアイテムを順番に返します | collection.stream()。skip(2).findFirst()。get() | a3 |
2番目から2つのアイテムを返します | collection.stream()。skip(1).limit(2).toArray() | [a2、a3] |
テンプレートごとにすべてのアイテムを選択します。 | collection.stream()。filter((s)-> s.contains( "1"))。collect(Collectors.toList()) | [a1、a1] |
findFirstおよびfindAnyメソッドは、NullPointerExceptionを回避するために、Java 8で導入された新しいOptional型を返すことに
注意して
ください 。 フィルターメソッドは、特定の値セットのみを選択するために便利に使用され、スキップメソッドでは、特定の数の要素をスキップできます。
ラムダがわからない場合式 "a3" :: equalsはブールfunc(s){return "a3" .equals(s);}の類似体であり、(s)-> s.contains( "1")はboolean func(s){return s.contains( "1");}は匿名クラスにラップされています。
条件 :コレクションがPeopleクラス(フィールド名-名前、年齢-年齢、性別-性別)、タイプArrays.asList(新しい人(「Vasya」、16、Sex.MAN)、新しい人(「Petya」、23、 Sex.MAN)、新しい人々( "Elena"、42、Sex.WOMEN)、新しい人々( "Ivan Ivanovich"、69、Sex.MAN))。 このクラスを操作する方法の例を見てみましょう。
挑戦する | サンプルコード | 結果 |
---|
兵役の責任者を選択してください(18歳から27歳まで) | peoples.stream()。filter((p)-> p.getAge()> = 18 && p.getAge()<27 && p.getSex()== Sex.MAN).collect(Collectors.toList()) | [{name = 'Petya'、年齢= 23、性別= MAN}] |
男性の平均年齢を見つける | peoples.stream()。filter((p)-> p.getSex()== Sex.MAN)。 mapToInt(People :: getAge).average()。getAsDouble() | 36.0 |
サンプル内の潜在的に健常な人の数を見つけます(つまり、18歳から、女性は55歳、男性は60歳であることを考慮して) | peoples.stream()。filter((p)-> p.getAge()> = 18).filter( (p)->(p.getSex()== Sex.WOMEN && p.getAge()<55)|| (p.getSex()== Sex.MAN && p.getAge()<60))。count() | 2 |
3.2 distinctの使用例
distinctメソッドは重複なしでストリームを返しますが、順序付きストリーム(リストベースのコレクションなど)の場合、順序は安定しています。順序なしストリームの場合、順序は保証されません。 コレクションCollection Order = Arrays.asList(「a1」、「a2」、「a2」、「a3」、「a1」、「a2」、「a2」)およびCollection nonOrdered = new HashSet <>(ordered )
挑戦する | サンプルコード | 結果 |
---|
順不同ストリームから重複のないコレクションを取得する | nonOrdered.stream()。distinct()。collect(Collectors.toList()) | [a1、a2、a3]- 順序は保証されません |
順序付けされたストリームから重複のないコレクションを取得する | ordered.stream()。distinct()。collect(Collectors.toList()); | [a1、a2、a3]- 注文保証 |
注意してください:1. equalsが再定義されたクラスでdistinctを使用する場合、equals / hashCodeコントラクト(最も重要なことは、すべてのequalsオブジェクトのhashCodeが同じ値を返すこと)に従ってhashCodeを正しく再定義することも必要です。 HashSet / HashMapを使用するときのように)、
2.並列ストリームを使用し、重複を削除した後、要素の順序を気にしない場合、並列ストリームでソートの安定性を維持するのは非常に高価なので、最初に順序なし()を使用してストリームを無秩序にし、次に別個の()を使用する方がパフォーマンスがはるかに優れています順序付けされたストリームのリソースと個別の()は、順序付けされていないストリームよりも完了するのにはるかに時間がかかります。
3.3一致関数の使用例(anyMatch、allMatch、noneMatch)
条件 :Arrays.asList文字列のコレクション(「a1」、「a2」、「a3」、「a1」)が与えられた場合、Match関数を使用してどのように処理できるかを見てみましょう
挑戦する | サンプルコード | 結果 |
---|
コレクションに少なくとも1つの「a1」アイテムが存在するかどうかを確認します。 | collection.stream()。anyMatch( "a1" ::等しい) | 本当 |
コレクションに少なくとも1つの「a8」要素が存在するかどうかを調べます | collection.stream()。anyMatch( "a8" ::等しい) | 偽 |
コレクションのすべての要素に記号「1」があるかどうかを調べます | collection.stream()。allMatch((s)-> s.contains( "1")) | 偽 |
コレクションに「a7」アイテムが存在しないことを確認します。 | collection.stream()。noneMatch( "a7" ::等しい) | 本当 |
3.4 Map (map, mapToInt, FlatMap, FlatMapToInt)
: collection1 = Arrays.asList(«a1», «a2», «a3», «a1») collection2 = Arrays.asList(«1,2,0», «4,5»), map
挑戦する | | 結果 |
---|
"_1" | collection1.stream().map((s) -> s + "_1").collect(Collectors.toList()) | [a1_1, a2_1, a3_1, a1_1] |
(int[]) | collection1.stream().mapToInt((s) -> Integer.parseInt(s.substring(1))).toArray() | [1, 2, 3, 1] |
, | collection2.stream().flatMap((p) -> Arrays.asList(p.split(",")).stream()).toArray(String[]::new) | [1, 2, 0, 4, 5] |
, | collection2.stream().flatMapToInt((p) -> Arrays.asList(p.split(",")).stream().mapToInt(Integer::parseInt)).sum() | 12 |
: map (), map , Stream Integer People, Office, .., flatMap (flatMapToInt ..) , (. ).
3.5 Sorted
: Arrays.asList(«a1», «a4», «a3», «a2», «a1», «a4») People ( name — , age — , sex — ), Arrays.asList( new People(«», 16, Sex.MAN), new People(«», 23, Sex.MAN), new People(«», 42, Sex.WOMEN), new People(« », 69, Sex.MAN)). :
挑戦する | | 結果 |
---|
| collection.stream().sorted().collect(Collectors.toList()) | [a1, a1, a2, a3, a4, a4] |
| collection.stream().sorted((o1, o2) -> -o1.compareTo(o2)).collect(Collectors.toList()) | [a4, a4, a3, a2, a1, a1] |
| collection.stream().sorted().distinct().collect(Collectors.toList()) | [a1, a2, a3, a4] |
| collection.stream().sorted((o1, o2) -> -o1.compareTo(o2)).distinct().collect(Collectors.toList()) | [a4, a3, a2, a1] |
| peoples.stream().sorted((o1,o2) -> -o1.getName().compareTo(o2.getName())).collect(Collectors.toList()) | [{''}, {' '}, {''}, {''}]
|
, | peoples.stream().sorted((o1, o2) -> o1.getSex() != o2.getSex()? o1.getSex(). compareTo(o2.getSex()): o1.getAge().compareTo(o2.getAge())).collect(Collectors.toList()) | [{''}, {''}, {' '}, {''}] |
3.6 Max Min
: Arrays.asList(«a1», «a2», «a3», «a1»), Peoples Sorted Filter .
挑戦する | | 結果 |
---|
| collection.stream().max(String::compareTo).get() | a3 |
| collection.stream().min(String::compareTo).get() | a1 |
| peoples.stream().max((p1, p2) -> p1.getAge().compareTo(p2.getAge())).get() | {name=' ', age=69, sex=MAN} |
| peoples.stream().min((p1, p2) -> p1.getAge().compareTo(p2.getAge())).get() | {name='', age=16, sex=MAN} |
3.7 ForEach Peek
ForEach Peek , , ForEach , Peek . , :
Collection<StringBuilder> list = Arrays.asList(new StringBuilder("a1"), new StringBuilder("a2"), new StringBuilder("a3"));
"_new", ForEach
list.stream().forEachOrdered((p) -> p.append("_new"));
peek
List<StringBuilder> newList = list.stream().peek((p) -> p.append("_new")).collect(Collectors.toList());
3.8 Reduce
reduce ( , ..), , — .
: Arrays.asList(1, 2, 3, 4, 2) reduce.
挑戦する | | 結果 |
---|
0 | collection.stream().reduce((s1, s2) -> s1 + s2).orElse(0) | 12 |
-1 | collection.stream().reduce(Integer::max).orElse(-1) | 4 |
0 | collection.stream().filter(o -> o % 2 != 0).reduce((s1, s2) -> s1 + s2).orElse(0) | 4 |
3.9 toArray collect
toArray , toArray() Object[], toArray(T[]::new) — T, collect , map' . Collectors, List stream.collect(Collectors.toList()).
Collectors:
方法 | 説明 |
---|
toList, toCollection, toSet | , |
toConcurrentMap, toMap | map |
averagingInt, averagingDouble, averagingLong | |
summingInt, summingDouble, summingLong | |
summarizingInt, summarizingDouble, summarizingLong | SummaryStatistics |
partitioningBy | Map<Boolean, List> |
groupingBy | Map<N, List<T>> |
mapping | Collector' |
collect toArray :
: Arrays.asList(1, 2, 3, 4), collect toArray
挑戦する | | 結果 |
---|
| numbers.stream().collect(Collectors.summingInt(((p) -> p % 2 == 1? p: 0))) | 4 |
1 | numbers.stream().collect(Collectors.averagingInt((p) -> p — 1)) | 1.5 |
3 | numbers.stream().collect(Collectors.summarizingInt((p) -> p + 3)) | IntSummaryStatistics{count=4, sum=22, min=4, average=5.5, max=7} |
| numbers.stream().collect(Collectors.partitioningBy((p) -> p % 2 == 0)) | {false=[1, 3], true=[2, 4]} |
: Arrays.asList(«a1», «b2», «c3», «a1»), collect toArray
挑戦する | | 結果 |
---|
| strings.stream().distinct().collect(Collectors.toList()) | [a1, b2, c3] |
| strings.stream().distinct().map(String::toUpperCase).toArray(String[]::new) | {A1, B2, C3} |
: <b>… </b> | strings.stream().collect(Collectors.joining(": ", "<b> ", " </b>")) | <b> a1: b2: c3: a1 </b> |
map, , | strings.stream().distinct().collect(Collectors.toMap((p) -> p.substring(0, 1), (p) -> p.substring(1, 2))) | {a=1, b=2, c=3} |
map, | strings.stream().collect(Collectors.groupingBy((p) -> p.substring(0, 1))) | {a=[a1, a1], b=[b2], c=[c3]} |
map, : | strings.stream().collect(Collectors.groupingBy((p) -> p.substring(0, 1), Collectors.mapping((p) -> p.substring(1, 2), Collectors.joining(":")))) | {a=1:1, b=2, c=3} |
3.10 Collector'a
Collector' Collectors Collector, .
Collector'a:
Collector<_, _, _> ollector = Collector.of( __, ___, ___, [___] );
, Collector'a (___ ). , Java 8, :
StringBuilder b = new StringBuilder();
, Java 8
String joinBuilder = strings.stream().collect( Collector.of( StringBuilder::new,
-, , , ___? Collector'a, ( ), StringBuilder , Java 8 2 :
StringBuilder b1 = new StringBuilder();
Collectors.toList() :
IV。 おわりに
以上です。 , stream api .
github' , .
PS , Stream Api:
1.
Processing Data with Java SE 8 Streams, Part 1 Oracle,
2.
Processing Data with Java SE 8 Streams, Part 2 Oracle,
3.
Java 8 StreamPPS opensource
useful-java-links — , Java , .
opensource
Hello world Java maven ( ).