【问题标题】:How to use org.w3c.dom.NodeList with Java 8 Stream API?如何将 org.w3c.dom.NodeList 与 Java 8 Stream API 一起使用?
【发布时间】:2014-06-15 03:10:26
【问题描述】:

我相信接口org.w3c.dom.NodeList 缺少stream() 函数以利用Java 8 的Stream API 的优势。考虑到引入默认方法以确保向后兼容,我不明白为什么这个接口没有stream() 功能。

所以我的问题是:

  • 如何将NodeList 与 Stream API 结合使用?
  • 如果不鼓励这样做,原因是什么?

提前致谢!

编辑:我目前正在使用这个实用程序包装器:

private static Stream<Node> nodeStream(NodeList list) {
    List<Node> nodes = new ArrayList<>();

    for (int n = 0; n < list.getLength(); ++n) {
        nodes.add(list.item(n));
    }

    return nodes.stream();
}

【问题讨论】:

    标签: java dom


    【解决方案1】:

    DOM 是一头奇怪的野兽,API 由 W3C 以独立于语言的方式定义,然后映射到各种不同的编程语言中,因此 Java 无法在核心 DOM 接口中添加任何特定于 Java 的内容。首先是 DOM 规范的一部分。

    因此,虽然您不能将NodeList as 用作流,但您可以轻松地 NodeList 创建流,例如使用

    Stream<Node> nodeStream = IntStream.range(0, nodeList.getLength())
                                       .mapToObj(nodeList::item);
    

    但是,有一个重要的警告 - DOM NodeList活动的,它反映了自创建列表以来对原始 DOM 树的更改。如果您在 DOM 树中添加或删除元素,它们可能会神奇地从现有的 NodeList 中出现或消失,如果这发生在迭代中间,这可能会导致奇怪的效果。如果你想要一个“死”节点列表,你需要将它复制到一个数组或列表中,就像你已经在做的那样。

    【讨论】:

    • 更新节点时是否触发了事件?有什么方法可以在文档更改时实时更新 GUI 中的文本?
    【解决方案2】:

    考虑到引入默认方法来保证向后兼容,我不明白为什么这个接口没有stream()函数。

    接口是在 Java 8 存在之前定义的。由于Stream 在 Java 8 之前不存在,因此NodeList 无法支持它。

    如何将 NodeList 与 Stream API 结合使用?

    你不能。至少,不是直接的。

    如果不鼓励这样做,原因是什么?

    这不是“气馁”。而是不支持。

    主要原因是历史。见上文。

    负责为 Java 指定 org.w3c.dom API 的人(即 W3 联盟)可能会推出对 Java 8 更友好的 API 的新版本。但是,这会引入一堆新的兼容性问题。新版本的 API 不会与当前版本二进制兼容,也不会与 Java 8 之前的 JVM 兼容。


    但是,这比让 W3 联盟更新 API 更复杂。

    DOM API 是在 CORBA IDL 中定义的,而 Java API 是通过将 CORBA Java 映射应用到 IDL 来“生成”的。此映射由 OMG 指定……而不是 W3 联盟。因此,创建org.w3c.dom API 的“Java 8 流友好”版本将需要让 OMG 更新 CORBA Java 映射以支持Stream(至少从 CORBA 兼容性的角度来看这是有问题的)或破坏Java API 和 CORBA 之间的连接。

    不幸的是,在刷新 IDL 到 Java 映射的过程中,很难了解 OMG 世界中发生了什么(如果有的话)……除非您为 OMG 成员组织等工作。我没有。

    【讨论】:

    • 除非我误解了您的意思,否则您“由于 Stream 在 Java 8 之前不存在,因此 NodeList 无法支持它”的说法是没有意义的。该问题明确询问为什么没有将默认方法添加到 NodeList - 即类似于如何将默认流方法添加到 Collection。
    • 就像我说的,稍后在我的回答中,Oracle 不控制 API,让 OMG 和/或 W3C 修复它并不简单。所以这不仅仅是甲骨文“修复”它的问题。
    【解决方案3】:

    这是一个使用流来查找特定 NodeList 元素的示例:

    private String elementOfInterest;       // id of element
    private String elementOfInterestValue;  // value of element
    
    public boolean searchForElementOfInterest(Document doc)
    {
            boolean bFound=false;
            NodeList nList = doc.getElementsByTagName("entity");
    
            // since NodeList does not have stream implemented, then use this hack
            Stream<Node> nodeStream = IntStream.range(0, nList.getLength()).mapToObj(nList::item);
            // search for element of interest in the NodeList
            if(nodeStream.parallel().filter(this::isElementOfInterest).collect(Collectors.toList()).size() > 0)
                    bFound=true;
    
            return bFound;
    }
    
    private boolean isElementOfInterest(Node nNode)
    {
            boolean bFound=false;
            assert(nNode != null);
            if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;
                    String id = eElement.getElementsByTagName("id").item(0).getTextContent();
                    String data = eElement.getElementsByTagName("data").item(0).getTextContent();
                    if (id.contentEquals(elementOfInterest) && data.contentEquals(elementOfInterestValue))
                            bFound = true;
            }
            return bFound;
    }
    

    【讨论】:

    • 请注意,要确定流是否具有匹配条件的元素,在Stream 类上使用anyMatch(Predicate) 方法会更有效(也更容易阅读)。例如,在上面,您可以简单地说:return nodeStream().parallel().anyMatch(this::isElementOfInterest);
    【解决方案4】:

    java8 Stream.iterate
    像这样使用:

        Stream.iterate(0, i -> i + 1)
              .limit (nodeList.getLength())
              .map (nodeList::item).forEach...
    

    对于java9 iterate,有一个迭代的增强版本,而以前的版本也可用:

        Stream.iterate(0, i -> i < nodeList.getLength(), i -> i + 1)
              .map (nodeList::item).forEach...
    

    两个版本的迭代在 Java14 中仍然相同

    【讨论】:

      猜你喜欢
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      • 2014-07-13
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-12
      相关资源
      最近更新 更多