2

how could I set my object to another in lambda expression? I got error

variable used in lambda expression should be final or effectively final

with following code:

public MyObj myFun(MyObj o) {
   MyObj obj = null;

   myObjList.stream().filter(o -> ...).forEach(o -> {
      // I do some stuff here

      // I need here set obj to o, but I got error
      obj = o;
   });

   return myObj; // I need return found obj or null;
}
Denis Stephanov
  • 4,563
  • 24
  • 78
  • 174
  • 1
    So you're trying to find the last object in the list that matches the condition? If so, this could be a duplicate of [this question](https://stackoverflow.com/q/21426843). – Dawood ibn Kareem Oct 30 '17 at 19:13
  • 1
    You should use a collector. – SLaks Oct 30 '17 at 19:13
  • 1
    no you are not allowed to do this in Java. state your actual end goal. – Jason Hu Oct 30 '17 at 19:15
  • @DawoodibnKareem no, I am looking for some specific object in list, and next do some operations with that object, and on the end, set its to variable which I return, or variable stay null; – Denis Stephanov Oct 30 '17 at 19:18
  • 1
    @DenisStephanov ok, but what should happen if there are multiple Elements that match your filter? Should it just use the first one? Or anyone? – Thomas Böhm Oct 30 '17 at 19:19
  • that is not possible because I filter by unique id. – Denis Stephanov Oct 30 '17 at 19:20
  • 1
    @DenisStephanov you’re looking for findFirst. – Ousmane D. Oct 30 '17 at 19:21
  • @Aominè I think he wants `obj` to end up being the _last_ object that matches the condition, not the _first_. Unless, of course, there's only one such object; but he hasn't stated this. – Dawood ibn Kareem Oct 30 '17 at 19:23
  • @DawoodibnKareem OP said “ I filter by unique Id” ;) – Ousmane D. Oct 30 '17 at 19:24
  • But how this solve my problem? I need do operations with founded object, also update some values in this object, and on the end set it into variable which I return on the on of function, but I can't due to error. – Denis Stephanov Oct 30 '17 at 19:27
  • "Effectively final" mean that your code should work if you actually added the "final" keyword to the variable. Setting it violates this requirement. – Thorbjørn Ravn Andersen Oct 30 '17 at 19:31
  • 1
    @Aominè Ooh, you're right. I missed that. So `findFirst` would be a really good solution then. Frankly though, if I were writing this, I'd use a good old for-each loop and an if statement. – Dawood ibn Kareem Oct 30 '17 at 19:33
  • @ThorbjørnRavnAndersen for a variable to be effectively final it need not be declared final rather it needs not be reassigned after being assigned the first time. – Ousmane D. Oct 30 '17 at 19:36
  • @Aominè Would "should _still_ work" be better. The whole point of "effectively final" is that the variable is used as if it was declared final. – Thorbjørn Ravn Andersen Oct 30 '17 at 19:48

3 Answers3

5

You can't assign o to the outer variable. But you can return it as a result of you stream processing. Use map instead of forEach and return o from the mapper. Then do findAny or findFirst - this will give you an Optional<MyObj>. Finally do orElse(null) to return the found and processed object or null if none was found.

MyObj obj = myObjList
   .stream()
   .filter(o -> ...)
   .map(o -> {
       // I do some stuff here

       // I need here set obj to o, but I got error
       return o;
   })
   .findAny()
   .orElse(null);
lexicore
  • 42,748
  • 17
  • 132
  • 221
1

Instead of using forEach instead consider using map(o->{...}).findFirst().get() (or similar depending on your logic if no item is relevant - your null case).

In general, you should let streams finish in a collector or a selector (findFirst/findAny etc.) because that will allow you to write simpler and clearer code

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
0

Instead of streaming through it, you could simply iterate through it in a loop and then return the value when you find it.

The streamy sort of answer is probably to use something like findFirst.

BillRobertson42
  • 12,602
  • 4
  • 40
  • 57