5

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?

lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

4 Answers4

8

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);
}
lealceldeiro
  • 14,342
  • 6
  • 49
  • 80
2

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
}
Manish Bansal
  • 2,400
  • 2
  • 21
  • 37
2

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()
MaanooAk
  • 2,418
  • 17
  • 28
0

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;
        }
    });
luca.vercelli
  • 898
  • 7
  • 24