ekjcfn3902039 ekjcfn3902039 - 2 months ago 7
Java Question

Convert logic to use Java 8 Streams

I am learning how to use Streams in Java 8, and would like to understand how to convert the following example to a stream-based way. I have made a couple attempts but can't get the stream-based way to compile. I think I'm getting tripped up with nested loops and variable references that seem to be lost.

import java.util.Collection;
import java.util.Objects;

import gov.geo.argcci.product.parts.layers.PlatformMarkerLayer;

public class Test {

public void java7Method(final Collection<Item> items) {
for (final LayerHolder layerHolder : getLayerHolders()) {
if (layerHolder.getLayer() instanceof MyLayer) {
final MyLayer myLayer = (MyLayer) layerHolder.getLayer();
final Item current = myLayer.getItem();
if (current != null) {
for (final Item item : items) {
if (Objects.equals(item.getSomeKey(), current.getSomeKey())
&& Objects.equals(item.getSomeOtherKey(), current.getSomeOtherKey())) {
final SomeObject someObject = getObjectBasedOnItem(current);
someObject.doSomething(layerHolder);
}
}
}
}
}
}

public void java8Method(final Collection<Item> items) {
getLayerHolders()
.stream()
.filter(layerHolder -> layerHolder.getLayer() instanceof MyLayer)
.map(layerHolder -> (MyLayer) layerHolder.getLayer())
.map(layerHolder -> layerHolder.getItem())
.filter(Objects::nonNull)
.forEach(current->{
items.stream()
.filter(Objects.equals(item.getSomeKey(), current.getSomeKey()) && Objects.equals(item.getSomeOtherKey(), current.getSomeOtherKey()));
// final SomeObject someObject = getObjectBasedOnItem(current);
// someObject.doSomething(layerHolder);
});
}

// The Code below this line is auto-generated to make sure example can compile without errors
private SomeObject getObjectBasedOnItem(Item current) {
return null;
}
private Collection<LayerHolder> getLayerHolders() {
return null;
}
private class Item {
public Object getSomeKey() {
return null;
}
public Object getSomeOtherKey() {
return null;
}
}
private class LayerHolder {
public MyLayer getLayer() {
return null;
}
}
private class MyLayer {
public Item getItem() {
return null;
}
}
private class SomeObject {
public void doSomething(LayerHolder layerHolder) {}
}
}

Answer

You need to use the outer layer object in the doSomething method. So you can't map to the Item object in the stream.

Probably the best decision is to try to simplify the design. Using streams is not going to make it more simple to implement.

In your version without streams, the inner for loop is testing if the item of the layer is inside the list, this could be another filter in the stream.

The code could be:

public void java8Method(final Collection<Item> items) {
    getLayerHolders()
    .stream()
    .filter(layerHolder -> layerHolder.getLayer() instanceof MyLayer)
    .filter(layerHolder -> Objects.nonNull(((MyLayer) layerHolder.getLayer()).getItem()))
    .filter(layerHolder->{ Item current = ((MyLayer) layerHolder.getLayer()).getItem();
                           return items.stream()
                                   .anyMatch(item->Objects.equals(item.getSomeKey(), current.getSomeKey()) && 
                                                   Objects.equals(item.getSomeOtherKey(), current.getSomeOtherKey())); })
    .forEach(layerHolder-> getObjectBasedOnItem(((MyLayer) layerHolder.getLayer()).getItem()).doSomething(layerHolder));
}
Comments