我在使用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()
来隔离我想要识别的元素,但这似乎也就像发生的操作一样在流语句中的filter
或map
之后,不是在完整列表上运行,也不在列表中运行,其中每个项目都受.map()
的影响。
这似乎很简单,但我正在努力绕过它。因为初始查找本身是List
,所以我认为流可以替换所有这些。 ArrayList<>()
出现在原始代码中,但只要我能够通过其密钥替换该项目,项目的排序就不重要了。
如果您选择帮助,谢谢。
答案 0 :(得分:21)
您可以这样做:
List<Object> newItems = items.stream()
.map(o -> o.getPropValue() == newObject.getPropValue() ? newObject : o)
.collect(toList());
putIntoCache(newObject.getKey(), newItems);
答案 1 :(得分:2)
您要应用的功能是“替换匹配prop值的第一个元素”。 第一个部分(和break语句)非常重要(因为您依赖于之前处理的所有条目)。换句话说,它意味着您的函数依赖于一些额外的状态,因此域可以表示为boolean * String
,其中布尔值告诉您是否已完成替换。你可以看到它开始变得难看。
如果您可以替换所有匹配值,那么Jean Logeart的回答似乎没问题。
答案 2 :(得分:2)
Streams对于这段代码实际上并不是特别好,因为它有一个早期的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的回答。