【问题标题】:Simplifying loop with Java 8使用 Java 8 简化循环
【发布时间】:2017-03-02 10:44:27
【问题描述】:

我有一个将映射添加到缓存的方法,我想知道我可以做些什么来使用 Java 8 简化这个循环。

到目前为止我做了什么:
我们都知道的标准循环:

for(int i = 0; i < catalogNames.size(); i++){
    List<GenericCatalog> list = DummyData.getCatalog(catalogNames.get(i));
    Map<String, GenericCatalog> map = new LinkedHashMap<>();
    for(GenericCatalog item : list){
        map.put(item.name.get(), item);
    }
    catalogCache.put(catalogNames.get(i), map);};

使用 forEach 进行第二次迭代:

catalogNames.forEach(e -> {
    Map<String, GenericCatalog> map = new LinkedHashMap<>();
    DummyData.getCatalog(e).forEach(d -> {
        map.put(d.name.get(), d);
    });
    catalogCache.put(e, map);});

第三次迭代删除了不必要的括号:

catalogNames.forEach(objName -> {
    Map<String, GenericCatalog> map = new LinkedHashMap<>();
    DummyData.getCatalog(objName).forEach(obj -> map.put(obj.name.get(), obj));
    catalogCache.put(objName, map);});

我现在的问题是可以进一步做些什么来简化这一点?
我确实知道此时实际上没有必要用这种方法做任何其他事情,但是,我对这些可能性感到好奇。

【问题讨论】:

  • 提示:更短并不总是意味着更简单
  • 为什么要简化这个。我认为您的解决方案 #2 是构想的,您可以直接了解它的作用。
  • 正如我在问题中所说,我同意解决方案#2 和解决方案#3 既简单又简单(我在代码atm 中使用#2)。我只是好奇还能做些什么。

标签: java foreach java-8


【解决方案1】:

解决方案 2 和 3 存在小问题,它们可能会导致 side effects

行为参数对流操作的副作用是,在 一般,气馁,因为它们通常会导致不知情的违规行为 无状态要求,以及其他线程安全 危险。

作为如何转换流管道的示例, 不恰当地使用副作用的副作用,以下 代码在字符串流中搜索与给定正则匹配的字符串 表达式,并将匹配项放入列表中。

ArrayList<String> results = new ArrayList<>();
 stream.filter(s -> pattern.matcher(s).matches())
       .forEach(s -> results.add(s));  // Unnecessary use of side-effects!

因此,与其使用forEach 填充HashMap,不如使用Collectors.toMap(..)。我不是 100% 确定您的数据结构,但我希望它足够接近。

有一个List和对应的Map

List<Integer> ints = Arrays.asList(1,2,3);

Map<Integer,List<Double>> catalog = new HashMap<>();
catalog.put(1,Arrays.asList(1.1,2.2,3.3,4.4));
catalog.put(2,Arrays.asList(1.1,2.2,3.3));
catalog.put(3,Arrays.asList(1.1,2.2));

现在我们想要获得一个新的Map,其中映射key 是原始List 的元素,map value 是另一个Map 本身。嵌套的 Map's 键是从 catalog List 转换的元素,valueList 元素本身。疯狂的描述和更疯狂的代码如下:

Map<Integer, Map<Integer, Double>> result = ints.stream().collect(
        Collectors.toMap(
                el -> el, 
                el -> catalog.get(el).stream().
                        collect(Collectors.toMap(
                                c -> c.intValue(), 
                                c -> c
                        ))

        )
);
System.out.println(result);
// {1={1=1.1, 2=2.2, 3=3.3, 4=4.4}, 2={1=1.1, 2=2.2, 3=3.3}, 3={1=1.1, 2=2.2}}

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    如何利用流 API 中的收集器?具体来说,Collectors#toMap

    Map<String, Map<String, GenericCatalog>> cache = catalogNames.stream().collect(Collectors.toMap(Function.identity(),
        name -> DummyData.getCatalog(name).stream().collect(Collectors.toMap(t -> t.name.get(), Function.identity(),
                //these two lines only needed if HashMap can't be used
                (o, t) -> /* merge function */,
                LinkedHashMap::new));
    

    这避免了改变现有集合,并为您提供了您自己的地图副本(您可以使用它来更新缓存或任何您想要的)。

    另外,我不同意在一行代码的末尾随意放置大括号 - 大多数样式指南也会反对这一点,因为它在某种程度上扰乱了大多数读者的代码流。

    【讨论】:

      猜你喜欢
      • 2020-11-23
      • 1970-01-01
      • 2017-03-16
      • 2015-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多