简体   繁体   English

转换逻辑以使用Java 8流

[英]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. 我正在学习如何在Java 8中使用Streams,并且想了解如何将以下示例转换为基于流的方式。 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) {}
    }
}

A direct translation of your Java 7 code would be Java 7代码的直接翻译是

public void java8Method(final Collection<Item> items) {
    getLayerHolders().forEach(layerHolder -> {
        Optional.of(layerHolder)
                .map(LayerHolder::getLayer)
                .filter(MyLayer.class::isInstance)
                .map(l -> ((MyLayer)l).getItem())
                .ifPresent(current-> items.stream()
                    .filter(item ->
                        Objects.equals(item.getSomeKey(), current.getSomeKey())
                     && Objects.equals(item.getSomeOtherKey(), current.getSomeOtherKey()))
                    .forEach(ignored ->
                             getObjectBasedOnItem(current).doSomething(layerHolder))
            );
    });
}

except that this doesn't call getLayer() twice. 除了不会两次调用getLayer()

But I have the strong feeling that what you actually want to do is 但是我有一种强烈的感觉,你真正想做的是

public void java8Method(final Collection<Item> items) {
    getLayerHolders().forEach(layerHolder ->
        Optional.of(layerHolder)
                .map(LayerHolder::getLayer)
                .filter(MyLayer.class::isInstance)
                .map(l -> ((MyLayer)l).getItem())
                .filter(current-> items.stream()
                    .anyMatch(item ->
                        Objects.equals(item.getSomeKey(), current.getSomeKey())
                     && Objects.equals(item.getSomeOtherKey(), current.getSomeOtherKey())))
                .ifPresent(current ->
                           getObjectBasedOnItem(current).doSomething(layerHolder))
    );
}

Generally, you should think more about the actual program logic than converting pre-Java 8 code to Stream API using code… 通常,您应该更多地考虑实际的程序逻辑,而不是使用代码将Java 8之前的代码转换为Stream API。

You need to use the outer layer object in the doSomething method. 您需要在doSomething方法中使用外层对象。 So you can't map to the Item object in the stream. 因此,您无法映射到流中的Item对象。

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. 在没有流的版本中,内部for循环正在测试图层的项目是否在列表内,这可能是流中的另一个过滤器。

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));
}

Trying to make it a single streaming function makes it very difficult to read and maintain. 试图使其成为单个流功能使其很难读取和维护。

Implementing it in stages and breaking out Predicates would be ideal. 分阶段实施它并突破谓词将是理想的。

This implementation gets you both readable, maintainable code and streaming functionality. 此实现使您既可读又可维护的代码以及流式传输功能。

public void java8Method(Collection<Item> items)
  {
    Predicate<LayerHolder> hasMyLayer = lh -> MyLayer.class
        .isInstance(lh.getLayer());

    Predicate<MyLayer> hasNonNullItem = ml -> Objects.nonNull(ml.getItem());

    Predicate<MyLayer> hasMatchingItem = (ml) -> items.stream()
        .filter(i -> i.getSomeKey().equals(ml.getItem().getSomeKey()))
        .filter(i -> i.getSomeOtherKey().equals(ml.getItem().getSomeOtherKey()))
        .count() > 0;

    getLayerHolders().stream().filter(lh -> hasMyLayer.test(lh))
        .filter(lh -> hasNonNullItem.test(lh.getLayer()))
        .filter(lh -> hasMatchingItem.test(lh.getLayer()))
        .forEach(lh -> getObjectBasedOnItem(lh.getLayer().getItem())
            .doSomething(lh));
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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