问题
I would like to use local variables in lambda functions but I get error: Please see the 1. and 2. points in the code.
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
}
}
How can I use them whitout setting them as global variables ?
回答1:
You can't use an int as variable because it must be final to be used in a stream.
But You can create a class wrapping the int.
Then declare the variable holding this class as final.
Changing the content of the inner int variable.
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;
}
回答2:
forEach
is the wrong tool for the job.
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();
Or just use nested for loops:
int d = 0;
for (List<Route> rs : routeLists) {
for (Route r : rs) {
d += r.getDistance();
}
}
回答3:
Having side effects is discouraged (or even forbidden?) in the functions used in a stream.
A better way would be one of
routeLists.stream()
.flatMapToInt(innerList -> innerList.stream()
.mapToInt(Route::getDistance))
.sum()
or
routeLists.stream()
.mapToInt(innerList -> innerList.stream()
.mapToInt(Route::getDistance).sum())
.sum()
The first will, for each sublist, create a stream of distances. All these streams will become flattened and summed at once.
The second will create the sum of each sublist and then add all those sums together again.
They should be equivalent, but I am not sure if the one or other is better in terms of performance (i. e., if flattening the streams is more expensive than summing).
A third alternative of flattening the lists and then getting and summing the distances is covered by Andy Turner's answer.
来源:https://stackoverflow.com/questions/49273149/java-8-local-variable-in-stream-foreach