简体   繁体   中英

Java8 stream with nested objects

So I'm new to Java8. I've read about streams, but most examples are very basic. I was wondering how it'd be done with nested objects. Here is an example from my code:

for (Gas gas : gases) {
  resourceNodes.add(gas.getRefinery().unit());
}

It seems like I should be able to one-line this with a stream, but I can't quite figure it out. Could someone provide an answer with a stream. Is there a way to use:: syntax with nested methods too?

Edit: To clarify the example, getRefinery() returns an object of type: UnitInPool, whose method unit() returns an object of type: Unit. resourceNodes is an ArrayList of Unit.

The :: syntax that you refer to is what's known as a method reference .


Assuming resourceNodes is unassigned (or empty, in which case you can remove any previous assignment) prior to the for-loop, then you'd want to first map each Gas to whatever type unit() returns, and then collect the Stream to a List :

resourceNodes = gases.stream()
                     .map(Gas::getRefinery)
                     .map(GasRefinery::unit)
                     .collect(Collectors.toList());

Otherwise, if your goal is to simply add to resourceNodes , then it would be very similar:

resourceNodes.addAll(gases.stream()
                          .map(Gas::getRefinery)
                          .map(GasRefinery::unit)
                          .collect(Collectors.toList()));

You need to provide more code for a reasonable answer, but I'm guessing you can get a stream of units, whetever these are (and whatever getRefinery returns) this way:

gases.stream().map(Gas::getRefinery).map(???::unit)

then you can for example collect the result with collect(Collectors.toList()) and just call resourceNodes.addAll with the collected result as parameter

resourceNodes = gases.stream().map(gas -> gas.getRefinery().unit()).collect(Collectors.toList());

If you want only method references, you can use this:

gases.stream().map(Gas::getRefinery).map(UnitInPool::unit).map(resourceNodes::add);
or
gases.stream().map(Gas::getRefinery).map(UnitInPool::unit).forEach(resourceNodes::add);

Otherwise, a lambda would likely be better since it's a lot shorter and more readable, and works, when you have methods that take multiple parameters or need to do multiple complex operations.

gases.stream().forEach(g -> resourceNodes.add(g.getRefinery().unit()));

This is basically the same as your previous code, but I would suggest the for-loop.

Welcome to the SO community. I hope the following helps.

List<Unit> resourceNodes = gases.stream() // open a stream
.map(gas -> gas.getRefinery()) // convert to UnitInPool
.filter(unitInPool -> Objects.nonNull(unitInPool)) // null check to avoid NPE
.map(unip -> unip.getUnit()) // convert to Unit
.collect(Collectors.toList()) // collect all the values in a List

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM