Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In java 8 lambdas, how to access original object in the stream?

Let's say I have a list of 'A'

List<A> as;

If I want to do a fair bit of processing on each A, and at the end of the processing, I want to take the result and put it in another field of A, what is the best way to do that?

ie

as.stream().
map(a -> a.getX()).
filter(x -> x != null).
map(x -> lookup.get(x)).

At this point how to say y -> a.setLookedUpVal(y)?

I've lost the reference to 'a' further up in the lambda chain. Is there any way to store it and refer back to it or something?

like image 489
user1471465 Avatar asked May 18 '16 12:05

user1471465


People also ask

How do I find the first element of a stream?

To get the first element, you can directly use the findFirst() method. This will return the first element of the stream.

How do you use lambda in stream?

To use this, you specify a tumbling window duration in the event-source mapping between the stream and the Lambda function. When you apply a tumbling window to a stream, items in the stream are grouped by window and sent to the processing Lambda function.

Does stream filter modify the original array?

stream(). filter(i -> i >= 3); does not change original list. All stream operations are non-interfering (none of them modify the data source), as long as the parameters that you give to them are non-interfering too.

Which method can be use to get the stream object from any collection?

The collect() method of Stream class can be used to accumulate elements of any Stream into a Collection.


2 Answers

If you have more complex scenario or don't like @Aaron answer for some reason, you can do the flatMap-capturing trick creating one-element stream per each outer element:

as.stream().
   flatMap(a -> Stream.of(a.getX()).
      filter(x -> x != null).
      map(x -> a)).
   forEach(System.out::println);

Here we have nested per-element stream where you can do any stateless stream operations (map, filter, peek and flatMap) having a reference to the original element. After original element becomes unnecessary, you close the flatMap and continue with original stream. Example:

Stream.of("a", "bb", "ccc", "dd", "eeee")
    .flatMap(a -> Stream.of(a.length())
            .filter(x -> x > 2)
            .map(x -> a))
    .forEach(System.out::println);
// prints "ccc" and "eeee".

Or two filters:

Stream.of("a", "bb", "ccc", "dd", "eeee")
    .flatMap(a -> Stream.of(a.length())
            .filter(x -> x > 2)
            .map(x -> a.charAt(0)) // forget the length, now check the first symbol
            .filter(ch -> ch == 'c')
            .map(x -> a)) // forget the first symbol, reverting to the whole string
    .forEach(System.out::println);
// prints only "ccc"

Of course such simple scenarios could be rewritten like @Aaron suggests, but in more complex cases flatMap-capturing may be suitable solution.

like image 116
Tagir Valeev Avatar answered Sep 30 '22 07:09

Tagir Valeev


I don't know if you can access the unmodified elements, but you could rework your operations chain in the following way :

as.stream()
  .filter(a -> a.getX() != null)
  .forEach(a -> a.setLookedUpVal(lookup.get(a.getX()))

Now I understand it makes it more complex and might not be interesting in solving your real-world problem.
It has, however, the advantage of working all along with a Stream<A>, which could in some situations make it simpler and more extensible than having different types at different steps.

like image 35
Aaron Avatar answered Sep 30 '22 07:09

Aaron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!