Java流,通过收集替换foreach

时间:2017-07-27 12:27:59

标签: java java-stream

有没有更好的方法用Java 8流填充zoo

我想可能有使用map / flatMap / collect的解决方案?

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Main {

    public static void main(String args[])
    {
        List<Animal> zoo = new ArrayList<>();

        List<String> animals = new ArrayList<>();
        animals.add("cat");
        animals.add("dog");
        animals.add("donkey");

        Map<String, List<String>> houses = new ConcurrentHashMap<>();
        houses.put("cat", Arrays.asList("white house", "black house"));
        houses.put("dog", Arrays.asList("blue house"));
        houses.put("donkey", Arrays.asList("black house"));

        Map<String, List<String>> planets = new ConcurrentHashMap<>();
        planets.put("white house", Arrays.asList("earth", "mars"));
        planets.put("green house", Arrays.asList("earth", "jupiter"));
        planets.put("blue house", Arrays.asList("jupiter", "mars"));
        planets.put("black house", Arrays.asList("mars"));

        animals.parallelStream().forEachOrdered(s ->
                {
                    houses.get(s).parallelStream().forEachOrdered(s1 ->
                            {
                                System.out.println(s1);
                                planets.get(s1).parallelStream().forEachOrdered(s2 ->
                                        {
                                            zoo.add(new Animal(s, s1, s2));
                                        }
                                );
                            }
                    );
                }
        );

        System.out.println(zoo);

    }

    static final class Animal {
        private String name;
        private String house;
        private String planet;

        Animal(String name, String house, String planet) {
            this.name = name;
            this.house = house;
            this.planet = planet;
        }

    }
}

2 个答案:

答案 0 :(得分:2)

尝试以下解决方案:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class Main {

    public static void main(String args[]) {
        final List<String> animals = new ArrayList<>();
        animals.add("cat");
        animals.add("dog");
        animals.add("donkey");

        final Map<String, List<String>> houses = new ConcurrentHashMap<>();
        houses.put("cat", Arrays.asList("white house", "black house"));
        houses.put("dog", Arrays.asList("blue house"));
        houses.put("donkey", Arrays.asList("black house"));

        final Map<String, List<String>> planets = new ConcurrentHashMap<>();
        planets.put("white house", Arrays.asList("earth", "mars"));
        planets.put("green house", Arrays.asList("earth", "jupiter"));
        planets.put("blue house", Arrays.asList("jupiter", "mars"));
        planets.put("black house", Arrays.asList("mars"));

        final List<Animal> zoo = animals.parallelStream()
                .map(animal -> houses.getOrDefault(animal, Collections.emptyList())
                        .parallelStream()
                        .map(house -> planets.getOrDefault(house, Collections.emptyList())
                                .parallelStream()
                                .map(planet -> new Animal(animal, house, planet))
                                .collect(Collectors.toList())
                        )
                        .flatMap(Collection::stream)
                        .collect(Collectors.toList())
                )
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

        zoo.forEach(System.out::println);
    }

    static final class Animal {
        private final String name;
        private final String house;
        private final String planet;

        Animal(String name, String house, String planet) {
            this.name = name;
            this.house = house;
            this.planet = planet;
        }

        @Override
        public String toString() {
            return "Animal{" +
                    "name='" + name + '\'' +
                    ", house='" + house + '\'' +
                    ", planet='" + planet + '\'' +
                    '}';
        }
    }
}

它将以下输出打印到控制台:

Animal{name='cat', house='white house', planet='earth'}
Animal{name='cat', house='white house', planet='mars'}
Animal{name='cat', house='black house', planet='mars'}
Animal{name='dog', house='blue house', planet='jupiter'}
Animal{name='dog', house='blue house', planet='mars'}
Animal{name='donkey', house='black house', planet='mars'}

编辑:我已经更新了示例以使用更紧凑的流示例。

答案 1 :(得分:1)

如果你重新设计你的程序,也许你想要完成的任何事情都会更容易。我不知道你想要怎样对你的动物园做什么,但据我所知,你的代码意图是你的意图,房子和星球不是动物的属性,但行星是房子的容器,房子是动物的容器。因此,您可以使用字段Animal定义一个类String name,一个类House,其中包含Collection<Animal>子类型的字段似乎最合适(可能是List<Animal>) ,以及类别为Planet的字段的Collection<House>类(在这种情况下,可能Set<House>可能更合适,取决于您要执行的操作)。此外,House需要检查它是否可以包含动物。如何最好地实施这取决于您的意图(例如,如果动物对房屋的适用性取决于动物本身,例如动物是否想要在特定的房屋中,则实施必须与适用性仅取决于房屋,例如,如果动物可以放入房屋内)。如果House和/或Planet直接实现Collection并且不仅仅是包装器,它可能会更方便,但这又取决于您的意图。

我知道这不是您问题的直接答案,但也许它解决了导致问题首先出现的问题(但不知道代码的上下文,我无法确定当然)。