【问题标题】:Java 8 stream: replace single item in streamed collectionJava 8 流:替换流式集合中的单个项目
【发布时间】:2016-04-18 21:32:20
【问题描述】:

我对使用 Java 8 有点陌生,我正在重构一些旧代码(这似乎是一个很好的用例)流操作。旧代码“有效”,但在我看来,它看起来效率非常低。

我的问题的简短版本是我正在尝试查找 List 的单个元素并将其替换为同一元素的更新版本(键是相同的,但每次代码时属性都有不同的值被调用)。

     try
     {
        List<Object> items = lookup(itemCache.getKey());
        for (int i = 0; i < items.size(); i++)
        {
           Object originalObject = items.get(i);
           if (originalObject.getPropValue() == newObject.getPropValue())
           {
              List<Object> newItems = new ArrayList<>(items);
              newItems.set(i, newObject);
              putIntoCache(newObject.getKey(), newItems);
              break;
           }
        }
     } 

     catch (Exception ex) { /*exception handling*/ }

根据我迄今为止所读到的关于流的内容,似乎我需要使用.map().filter() 来隔离我想要识别的元素,但这似乎也是在@987654324 之后发生的操作流语句中的@ 或map 将在不是完整列表或每个项目都受.map() 影响的列表上运行。

这似乎很简单,但我正在努力解决它。因为最初的查找是 List 本身,所以我认为流可以替换所有这些。 ArrayList&lt;&gt;() 出现在原始代码中,但项目的顺序并不重要,只要我能够用它的键替换该项目。

如果您选择提供帮助,谢谢。

【问题讨论】:

  • 流不适合源数据的mutations
  • 题外话,但如果您的缓存实现了Map,您可能会查看Map.computeIfPresent(UnaryOperator&lt;T&gt;),而不是读取List 并将其写回缓存。 computeIfAbsent 在 ConcurrentHashMap 中是线程安全的,这与这些答案中采用的读-修改-写方法不同。

标签: java java-stream


【解决方案1】:

你可以这样做:

List<Object> newItems = items.stream()
    .map(o -> o.getPropValue() == newObject.getPropValue() ? newObject : o)
    .collect(toList());
putIntoCache(newObject.getKey(), newItems);

【讨论】:

  • 这就是我要找的。感谢您的及时回复。
  • 注意语义差异。原始代码最多替换一次,如果未找到匹配项,则不执行任何操作,此代码将替换所有匹配项,并将始终创建并发布一个新列表。除此之外,您还可以将其简化为:items.stream().map(o -&gt; o.getPropValue() == newObject.getPropValue()? newObject: o).collect(toList())
  • 如果约定newItems是缓存中数据的可变副本,您可以使用newItems.replaceAll()而不是Stream
【解决方案2】:

Streams 实际上对于这种 sn-p 代码并不是特别好,因为它有一个早期的 break 并且同时适用于索引和元素。

你可以像这样构建一个等价的语句:

List<Object> items = lookup(itemCache.getKey());
IntStream.range(0, items.size())
    .filter(i -> items.get(i).getPropValue() == newItem.getPropValue())
    .findFirst()
    .ifPresent(i -> {
        List<Object> newItems = new ArrayList<>(items);
        newItems.set(i, newObject);
        putIntoCache(newObject.getKey(), newItems);
    });

真的更好吗?在我看来,并不特别。我们并没有真正使用任何流功能,只是用 API 替换控制流语法。

如果确切的行为不太重要,那么可能会有更好的例子,比如 Jean 的回答。

【讨论】:

    【解决方案3】:

    您要应用的功能是“替换与 prop 值匹配的 first 元素”。 first 部分(和 break 语句)并不重要(因为您依赖于在此之前处理的所有条目)。换句话说,它意味着你的函数依赖于一些额外的状态,所以域可以表示为boolean * String,其中 boolean 告诉你替换是否已经完成。你可以看到它开始变丑了。

    如果您可以替换 所有 个匹配值,那么 Jean Logeart 的答案似乎还可以。

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2015-10-20
      • 1970-01-01
      • 2015-06-29
      • 2014-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-22
      相关资源
      最近更新 更多