Reputation: 1678
I want to implement this endpoint with internal search:
@PostMapping("terminals_risk_filter/change_order/{terminalId}")
public ResponseEntity<?> updateFiltersPositions(@PathVariable Integer terminalId,
@RequestBody List<ChangeOrderRiskFiltersDTO> newFiltersPositionsList) {
List<RiskFilters> filterList = riskFilterService.findRiskFiltersByTerminalId(terminalId);
for (int i = 0; i < newFiltersPositionsList.size(); i++) {
// RiskFilters filter = filterList.findById(newFiltersPositionsList.get(i).getId());
Optional<RiskFilters> filter_payload = filterList.stream().filter(f -> newFiltersPositionsList.get(i).getId() == f.getId()).findAny();
RiskFilters filter = filter_payload.get();
filter.setPosition(newFiltersPositionsList.get(i).getPosition());
riskFilterService.save(filter);
}
return ok().build();
}
But I get error message Local variable i defined in an enclosing scope must be final or effectively final
Can you give me some advice how I can fix this issue, please? For example can I skip the for
cycle and use maybe stream into stream?
Upvotes: 6
Views: 21619
Reputation: 1038
This is not an answer to the original question.
The same error message appears if you try to assign a variable in an enclosing class from an inner anonymous class. For example:
int result = 0;
hibernateSession.doWork(new Work() {
@Override
public void execute(Connection conn) throws SQLException {
result = 1;
}
});
In this case, I found a workaround pointing to an array:
int[] result = new int[1];
hibernateSession.doWork(new Work() {
@Override
public void execute(Connection conn) throws SQLException {
result[0] = 1;
}
});
Upvotes: 1
Reputation: 14958
Can you give me some advice how I can fix this issue, please?
Why does this happen? You can read about it here: Lambdas: local variables need final, instance variables don't
Minimal changes to solve your problem: Don't use the i
variable itself. Create a copy of it and make it final
.
final int iCopy = i;
Optional<RiskFilters> filter_payload = filterList.stream().filter(f -> newFiltersPositionsList.get(iCopy).getId() == f.getId()).findAny();
For example can I skip the for cycle and use maybe stream into stream?
You could give it a try:
// replace the for-loop
// or just.... `newFiltersPositionsList.forEach(/* ... */)`
newFiltersPositionsList.stream().forEach(filterPosition -> {
Optional<RiskFilters> filter_payload = filterList.stream()
.filter(f -> filterPosition.getId() == f.getId())
.findAny();
RiskFilters filter = filter_payload.get();
filter.setPosition(filterPosition.getPosition());
riskFilterService.save(filter);
});
Also, you could use a for-each instead of a for-loop:
for (ChangeOrderRiskFiltersDTO filterPosition : newFiltersPositionsList) {
Optional<RiskFilters> filter_payload = filterList.stream()
.filter(f -> filterPosition.getId() == f.getId())
.findAny();
RiskFilters filter = filter_payload.get();
filter.setPosition(filterPosition.getPosition());
riskFilterService.save(filter);
}
Upvotes: 9
Reputation: 2468
If you want to avoid the simple solution of adding a final copy of the i, you can extract the actual "final" information:
final int id = newFiltersPositionsList.get(i).getId()
And your lambda can become:
f -> id == f.getId()
Upvotes: 2
Reputation: 2671
You can do it like below as well.
final ChangeOrderRiskFiltersDTO dto = newFiltersPositionsList.get(i);
Optional<RiskFilters> filter_payload = filterList.stream().filter(f -> dto.getId() == f.getId()).findAny();
if(filter_payload.isPresent()){
RiskFilters filter = filter_payload.get();
//More operations
}
Upvotes: 2