web-dev-qa-db-ja.com

Java 8は、ストリームチェーンを中断せずにStreamのすべての要素に関数を適用します

JavaにStreamチェーンを壊さずにStreamのすべての要素に関数を適用する方法はありますか? forEachを呼び出すことができますが、そのメソッドはvoidではなくStreamを返します。

27
alexgbelov

(少なくとも)3つの方法があります。サンプルコードのために、2つのコンシューマメソッドmethodAおよびmethodBを呼び出すと仮定しました。

A. peek()を使用します。

list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x));

ドキュメントは「デバッグ」のためにのみ使用すると述べていますが、動作します(そして、現在生産中です)

B. map()を使用してmethodAを呼び出し、要素をストリームに戻します。

list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x));

これはおそらく最も「受け入れられる」アプローチです。

C. forEach()で2つのことを行います。

list.stream().forEach(x -> {method1(x); methodB(x);});

これは柔軟性が最も低く、ニーズに合わない場合があります。

28
Bohemian

Streammap()関数を探しています。

例:

List<String> strings = stream
.map(Object::toString)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
4
csenga

最適なオプションは、ストリームにマップを適用することです。これは、たとえば次のように、このストリームの要素に指定された関数を適用した結果で構成されるストリームを返します。

IntStream.rangeClosed(40, 70).limit(20).mapToObj(i -> (Integer) i).map(item->item+3).map(item->item*2)... 

(StreamItemABCタイプのアイテムのストリーム)

ストリームにいくつかの変更を適用していますが、この方法では、引数をmapメソッドに渡して修正することはできません。

private void applyMethod(ParameterX parX) {
 someStreamX().map(n -> methodX(n, parX))...
}

private StreamItemABC methodX (StreamItemABC item, ParameterX parX) {
  return notification;
}
1
Mr.Q

breaking the stream chainの意味が完全にはわかりませんが、Streamを返すStreamの操作は、ストリームをbreakまたはconsumeしません。ストリームはterminal operationsによって消費され、forEach返さない a Stream<T>に注意して、forEachおよびforEachの前にすべてのintermediate操作を実行することにより、ストリームを終了します。自体。

コメントで提供した例では:

 myStream.map(obj -> {obj.foo(); return obj;}

ライナー1つでこれを行うことはできません。もちろん、メソッド参照を使用することもできますが、返されるStreamは異なる型になります(fooが型を返すと仮定します):

  myStream.map(Obj::foo) // this will turn into Stream<T>, where T is 
           // the return type of foo, instead of Stream<Obj>

それに加えて、map操作はstatefulであるため、強くお勧めしません。コードはコンパイルされ、希望どおりに機能する場合もありますが、後で失敗する可能性があります。 map操作はstatelessでなければなりません。

1
Eugene

Stream.peek を探していると思います。ただし、主にデバッグ方法として設計されているため、ドキュメントを注意深く読んでください。ドキュメントから:

このメソッドは、主にデバッグをサポートするために存在します。ここでは、パイプラインの特定のポイントを通過する要素を表示します。

peekに渡されるアクションは、 non-interfering でなければなりません。

最もクリーンな方法は、ストリーム内のオブジェクトにミューテーターを追加することだと思います。

例えば、

class Victim {
   private String tag;
   private Victim withTag(String t)
      this.tag = t;
      return this;
   }
}

List<Victim> base = List.of(new Victim());
Stream<Victim> transformed = base.stream().map(v -> v.withTag("myTag"));

必要に応じて(多くの場合)、withTagメソッドで新しいVictimを作成して返すことができます。これにより、Victimを不変にすることができます。

0
Roger Hayes