web-dev-qa-db-ja.com

java stream.foreachの8つのローカル変数

ラムダ関数でローカル変数を使用したいのですが、エラーが発生します。コードの1.ポイントと2.ポイントを参照してください。

class Foo {
    int d = 0; // 1. It compiles, but ugly, 2. doesnt compile
    public void findMax(List<List<Route>> routeLists) {
        int d = 0; // 2.Error : Local variable dd defined in an enclosing scope must be final or effectively final
        routeLists.forEach(e-> {
            e.forEach(ee -> {
                d+=ee.getDistance();    
            });

        });
        ... doing some other operation with d
    }
}

それらをグローバル変数として設定せずに使用するにはどうすればよいですか?

4
Csaba Prog

ストリームで使用するにはfinalである必要がありますであるため、intを変数として使用することはできません。

ただし、intをラップするクラスを作成できます。

次に、このクラスを保持する変数をfinalとして宣言します。

内部int変数の内容を変更します。

public void findMax(List<List<Route>> routeLists) {
        final IntWrapper dWrapper = new IntWrapper();
        routeLists.forEach(e-> {
            e.forEach(ee -> {
                dWrapper.value += ee.getDistance();    
            });

        });

        int d = dWrapper.value;

        ... doing some other operation with d
    }

 public class IntWrapper {
    public int value;
 }

forEachはその仕事には間違ったツールです。

int d =
    routeLists.stream()                // Makes a Stream<List<Route>>
        .flatMap(Collection::stream)   // Makes a Stream<Route>
        .mapToInt(Route::getDistance)  // Makes an IntStream of distances
        .sum();

または、ネストされたforループを使用します。

int d = 0;
for (List<Route> rs : routeLists) {
  for (Route r : rs) {
    d += r.getDistance();
  }
}
6
Andy Turner

ストリームで使用される関数では、副作用を持つことは推奨されていません(または禁止されていますか?)。

より良い方法は、

routeLists.stream()
    .flatMapToInt(innerList -> innerList.stream()
        .mapToInt(Route::getDistance))
    .sum()

または

routeLists.stream()
    .mapToInt(innerList -> innerList.stream()
        .mapToInt(Route::getDistance).sum())
    .sum()

1つ目は、サブリストごとに、距離のストリームを作成します。これらのストリームはすべてフラット化され、一度に合計されます。

2つ目は、各サブリストの合計を作成してから、それらすべての合計を再度加算します。

それらは同等である必要がありますが、パフォーマンスの点でどちらが優れているかはわかりません(つまり、ストリームをフラット化する方が合計よりもコストがかかるかどうか)。

リストをフラット化してから距離を取得して合計する3番目の方法は、 Andy Turnerの回答 でカバーされています。

1
glglgl