Java 8 Stream 在列表中查找元素

新手上路,请多包涵

我有以下课程:

 public class Item {
    int id;
    String name;
    // few other fields, contructor, getters and setters
}

我有一个项目列表。我想遍历列表并找到具有特定 ID 的实例。我正在尝试通过流来做到这一点。

 public void foobar() {

    List<Item> items = getItemList();
    List<Integer> ids = getIdsToLookup();
    int id, i = ids.size() - 1;

    while (i >= 0) {
        id = ids.get(i);
        Optional<Item> item = items
            .stream()
            .filter(a -> a.getId() == id)
            .findFirst();
        // do stuff
        i--;
    }
}

这是遍历列表并获取我需要的元素的最佳方式吗?此外,我在 id 的过滤器行上收到一条错误消息,指出 lambda 表达式中使用的变量必须是最终变量或实际上是最终变量。也许我可以在 while 循环中定义 id,这样应该可以消除异常。谢谢。

原文由 Gengis Khan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

如果您有很多要搜索的 ID,建议使用一次性完成的解决方案,而不是对每个 ID 进行线性搜索:

 Map<Integer,Optional<Item>> map=ids.stream()
    .collect(Collectors.toMap(id -> id, id -> Optional.empty()));
items.forEach(item ->
    map.computeIfPresent(item.getId(), (i,o)->o.isPresent()? o: Optional.of(item)));
for(ListIterator<Integer> it=ids.listIterator(ids.size()); it.hasPrevious();) {
    map.get(it.previous()).ifPresent(item -> {
        // do stuff
    });
}

第一条语句只是从 ids 列表中创建一个映射,将每个搜索 id 映射到一个空的 Optional

第二条语句使用 forEach 迭代项目,对于每个项目,它检查是否存在从其 id 到空的映射 Optional 并将其替换为 Optional 封装项目,如果有这样的映射,一次操作, computeIfPresent

最后一个 for 循环在 ids 列表上向后迭代,因为您希望按该顺序处理它们并在存在非空时执行操作 Optional -596由于地图是用列表中找到的所有 ID 初始化的, get 永远不会返回 null ,它将返回一个空的 Optional ,如果没有找到 id在 items 列表中。

这样,假设 Map 的查找具有 O(1) 时间复杂度,这是典型实现中的情况,净时间复杂度从 O(m×n) -c743 O(m+n) b 更改为 ---

原文由 Holger 发布,翻译遵循 CC BY-SA 3.0 许可协议

你可以尝试使用这样的东西:

 ids.forEach(id ->
    list.stream()
    .filter(p -> p.getId() == id)
    .findFirst()
    .ifPresent(p -> {
        // do stuff here
    });
);

Optional 这里表明你的过滤器方法可以返回一个空流,所以如果你调用 findFirst 它可以找到一个或零个元素。

原文由 ByeBye 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题