2017-12-13 11 views
3

私は、次のコードを持っている:fieldsが最終でなければなりませんので、動作しませんforEach内のラムダの外側にあるオブジェクトにアクセスする方法は?

String fields = ""; 
listofObjects.stream().forEach(l -> fields = fields + l.text); 

を。 lambdasを使用してfieldsを変更するにはどうすればよいですか?その仕事をする

+1

あなたは '' – alfasin

+1

は常にそのストリームラムダが並列に実行される可能性があります覚えておいてください) '.stream(の必要性を全くlistofObjects.forEach'ないでくださいすることができます - それが理由ですJavaは最終的な属性ではなく、誤って上書きすることを防ぎます – Mick

答えて

11

ストリームとラムダは一般にステートレスである必要があります。ここにあなたのケースのための従来の解決策です:

String fields = listofObjects.stream() 
     .map(l -> l.text) 
     .collect(Collectors.joining()); 
8

最小の変更は、だけではなく、StringBuilderを使用することです - それは、より効率的である:

StringBuilder builder = new StringBuilder(); 
listofObjects.stream().forEach(l -> builder.append(l.text)); 
String fields = builder.toString(); 

マーティンは指摘するとおり、Collectors.joining()は能力に参加する一般的な文字列を提供していますが、マップする必要がありますあなたのストリームを最初に文字列に変換します。 (mapとするのは簡単ですが、これを頻繁に行う必要がある場合は、独自のコレクタを作成して作成することができます)。

1

あなたは正確に同じことを行う必要がある場合:

StringBuilder builder = new StringBuilder(); 
listofObjects.stream().forEach(l -> builder.append(l.text)); 

しかし、より機能的なアプローチは、我々はreduceを使用することができます

fields = listofObjects.stream().map(l -> l.text).collect(Collectors.joining()); 
0

次のようになります。

String fields = listofObjects.stream() 
          .reduce((x, y) -> x + y).orElse(""); 

または、下記の@ shmoselさんのコメントにつき:

String fields = listofObjects.stream() 
          .reduce("", String::concat); 
+1

または '.reduce(" "、String :: concat);'。しかし、なぜこれのためにもっと効率的なコレクターがあるときに 'reduce()'を使うのでしょうか? – shmosel

+0

@shmosel trueの場合、reduceには、使用可能な初期値を持つ別のオーバーロードされたバージョンがあります。私は、あなたが提供した解決策ではなく、他のものを上回ることの付加価値を見ません。あなたはその1人にプロ/コンを見ますか? – alfasin

+1

私が提案したオーバーロードの値は、 'get()'コールを必要としないということです。これは一般に避けるべきです。 'Optional'オーバーロードを使用する場合は、少なくともOPの意図を反映するために' orElse( "") 'を使用してください。コレクターの価値は、間違いなくもっと慣用的であり、したがってより身近なことである。さらに、内部で 'StringJoiner'を使用しているため、繰り返し連結のコストがかかりません。 – shmosel

関連する問題