使用 Java 8 映射<String, Map<String, Car>> 到列表<Car>

Map<String, Map<String, Car>> to List<Car> using Java 8

假设我有标题中描述的结构:

Map<String, Map<String, Car>> mapNeighborhood

其中包含分别由地址和车牌索引的社区中的所有汽车。 我想 select 将所有红色汽车重新涂成黑色。为了完成该任务,我尝试 "flat" 两个地图并使用 Java 8 获取列表。一旦我获得列表,应用谓词我可以 select 仅红色汽车并应用重绘。

List<Car> listCars = new ArrayList<Car>();

mapNeighborhood.values().forEach(map -> map.values()
                                           .forEach(car -> listCars.add(car)));

listCars.stream().filter(Car::isRed)
                 .forEach(car -> car.repaint(Color.Black));

我相信您可以只使用 Java 8 中的一行来实现相同的效果,但我认为您可能会失去可读性。

我的问题是:是否有另一种不那么冗长的方法将地图展平为列表?也许使用 flatMap。提前致谢。

你不需要中级 List

mapNeighborhood.values().stream()
                        .flatMap(byPlate -> byPlate.values().stream())
                        .filter(Car::isRed)
                        .forEach(car -> car.repaint(Color.Black))

我认为这比您的代码可读,而且更短。它在客观上 更有效,无论是时间还是 space。


另请注意,Car::isRed 有点奇怪,因为您需要在 Car 上检查每个可能的 Color - 为本赛季添加一个新的 color,重新实现Car

Color::isRed 更有意义,使用 Car 实现 Colored 或类似的

interface Colored {
    Color getColor();
}

// in Color
public static boolean isRed(Colored colored) {
    return Objects.equals(colored.getColor(), RED);
}

我的结果与@Boris 相同,但我将向您展示如何使用 IntelliJ 实现它:

for (Map<String, Car> value : mapNeighborhood.values()) {
    for (Car car : value.values()) {
        if (car.isRed()) {
            car.repaint(Color.BLACK);
        }
    }
}

然后将光标移动到第一个 "for" 单词,按 Alt-Enter 然后选择 "Replace with ForEach",tada,我们开始:

mapNeighborhood.values().stream()
                        .flatMap(value -> value.values().stream())
                        .filter(Car::isRed)
                        .forEach(car -> car.repaint(Color.BLACK));

任何一种循环,你都可以尝试使用IntelliJ来帮助你智能地转换为java 8样式

这是我试过的一种方法

List<Car> collect = mapNeighborhood.values().stream()
                                            .map(Map::values)
                                            .flatMap(Collection::stream)
                                            .collect(Collectors.toList());

然后您可以继续操作汽车列表。

这很有用。

mapNeighborhood.values().stream()
                        .map(Map::values)
                        .flatMap(Collection::stream)
                        .filter(car -> car.getColor().equalsIgnoreCase("red"))
                        .forEach(car -> car.repaint("black"));