如何在Java 8中编写以下代码的可能方法

5

我有一段代码,目前可以正常运行,但我想将其重写为Java 8。





这段代码会生成一个Map。每个列表项都将分配给所有服务器。

public static Map<String, List<String>> agg(){
        List<String> list = Arrays.asList("Item A", "Item B", "Item C");
        List<String> servers = Arrays.asList("Server A", "Server B", "Server C", "Server D");
        Map<String, List<String>> map = new HashMap<>();
        for (int i = 0; i < list.size(); i++) {
            ArrayList<String> temp = new ArrayList<>();
            for (int j = 0; j < servers.size(); j++) {
                temp.add(servers.get(j));
            }
            map.put(list.get(i), temp);
        }
        return map;
    }


输出

Item C ::[Server A, Server B, Server C, Server D]
Item B ::[Server A, Server B, Server C, Server D]
Item A ::[Server A, Server B, Server C, Server D]

什么是lambda的等效方式?
4个回答

2
创建一个流来包含你的“items”,然后将它们收集到一个映射中,其中键是该流中的对象,值是服务器列表的副本。最初的回答。
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import static java.util.stream.Collectors.toMap;

...

List<String> servers = Arrays.asList("Server A", "Server B", "Server C", "Server D");
Map<String, List<String>> map = Stream.of("Item A", "Item B", "Item C")
    .collect(toMap(Function.identity(), (__) -> new ArrayList<>(servers)));

2

在将代码转换为lambda表达式之前,让我们简化它


 public static Map<String, List<String>> agg(){
    List<String> list = Arrays.asList("Item A", "Item B", "Item C");
    List<String> servers = Arrays.asList("Server A", "Server B", "Server C", "Server D");
    Map<String, List<String>> map = new HashMap<>();
    for (int i = 0; i < list.size(); i++) {
        map.put(list.get(i), new ArrayList<>(servers));
    }
    return map;
}

我只是简化了创建数组副本的过程。

在Java 8中,将数据从一种形式转换为另一种形式的流水线包含以下步骤:

  1. stream
  2. map(将数据从一种形式转换为另一种形式)
  3. reduce(过滤掉不需要的值)
  4. collect(收集结果)

由于您的数据不需要转换,只需要以不同的结构进行收集,因此不需要使用map和reduce。

最初的回答:

我简化了创建数组副本的过程。

在Java 8中,将数据从一种形式转换为另一种形式的流程包括以下步骤:

  1. 创建流
  2. 映射(将数据从一种形式转换为另一种形式)
  3. 归约(过滤掉不需要的值)
  4. 收集结果

由于您的数据不需要转换,只需要以不同的结构进行收集,因此不需要使用映射和归约。

public static Map<String, List<String>> agg(){
    List<String> list = Arrays.asList("Item A", "Item B", "Item C");
    List<String> servers = Arrays.asList("Server A", "Server B", "Server C", "Server D");

    Function<String, String> keyFunction = key -> key;
    Function<String, List<String>> valueFunction = key -> new ArrayList<>(servers);

    return list.stream()
            .collect(Collectors.toMap(keyFunction, valueFunction));
}

这些函数可以被内联,结果如下:

最初的回答:

    public static Map<String, List<String>> agg(){
    List<String> list = Arrays.asList("Item A", "Item B", "Item C");
    List<String> servers = Arrays.asList("Server A", "Server B", "Server C", "Server D");

    return list.stream()
            .collect(Collectors.toMap(key -> key, key -> new ArrayList<>(servers)));
}

你的答案是正确的,但抱歉我无法理解它。keyFunction和valueFunctions发生了什么? - mayank bisht
明白了你的回答。但我有一个问题。就像你说的,我们可以使用Stream、Map、Reduce和Collect操作。假设我想将列表名称与每个服务器名称连接起来,例如:Item A_Server A,Item A_Server B...,在这种情况下,我该如何编写map方法? - mayank bisht
在这种情况下,您需要将值函数更改为不同的内容。在这种情况下,您需要一个映射函数来转换这些值:Function<String,List<String>> valueFunction = key -> servers.stream().map(server -> key + "_" + server).collect(Collectors.toList()); - nucandrei
没错,我还在学习Java 8。你有什么学习资料可以分享吗?如果有的话,请告诉我。 - mayank bisht
我没有具体的参考资料可以供你学习,只有一些想法可以让学习过程更容易:1. 安装一个能够建议将现有代码更改为Lambda表达式的IDE(如Intellij IDEA)。确保你理解新代码中发生了什么。2. 将问题分解为流->映射->规约->收集流,并用Lambda等效结构替换它们。3. 在StackOverflow上搜索/提问如何解决特定场景的问题。 - nucandrei
显示剩余2条评论

1
一个简单的forEach方法如下:
Map<String, List<String>> output = new HashMap<>();
list.forEach(s -> output.put(s, servers));

0

试试这个:

list.stream()
            .map(item->new AbstractMap.SimpleEntry<>(item,servers))
            .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue));

不错的方法!但可能存在一个小问题:服务器列表在多个端点之间共享,可能会导致意想不到的问题。 - nucandrei
@nucandrei,你到底是什么意思? - Eugene
如果您在一个地方更改了列表,则使用对该列表的引用的所有人都将反映这些更改。除非这是期望的行为,否则有两个选项可以避免此问题:1-创建副本。2-使用不可变的结构。 - nucandrei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接