Подтвердить что ты не робот

Как использовать org.w3c.dom.NodeList с Java 8 Stream API?

Я считаю, что интерфейс 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();
}
4b9b3361

Ответ 1

DOM - странный зверь, API определен независимым от языка способом W3C, а затем отображается на различные языки программирования, поэтому Java не может добавить ничего, что характерно для Java для основных DOM-интерфейсов, t в спецификации DOM.

Итак, пока вы не можете использовать NodeList в качестве потока, вы можете легко создать поток из NodeList, используя, например,

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

Однако есть одно большое оговорка: DOM NodeList является живым и отражает изменения в исходном дереве DOM с момента создания списка. Если вы добавляете или удаляете элементы в дереве DOM, они могут появляться или исчезать из существующих NodeLists, и это может вызвать странные эффекты, если это происходит в середине итерации. Если вам нужен "мертвый" node список, вам нужно будет скопировать его в массив или список, как вы уже делаете.

Ответ 2

Учитывая внедрение методов по умолчанию для обеспечения обратной совместимости, я не понимаю, почему этот интерфейс не имеет функции stream().

Интерфейс был определен до того, как существовала Java 8. Поскольку Stream не существовало до Java 8, это означает, что NodeList не может его поддерживать.

Как использовать NodeList в сочетании с Stream API?

Вы не можете. По крайней мере, не напрямую.

Если это обескураживает это, каковы причины этого?

Он не "обескуражен". Скорее, он не поддерживается.

Основная причина - история. См. Выше.

Возможно, что люди, ответственные за указание API-интерфейсов org.w3c.dom для Java (т.е. консорциум W3), выведут новую версию API, которая будет более дружественной к Java 8. Однако это приведет к появлению группы новых проблем совместимости. Новая редакция API не будет бинарной совместимостью с текущими и не будет совместима с JVM до Java 8.


Однако это сложнее, чем просто получить W3 Consortium для обновления API.

API DOM определены в IDL CORBA, а API-интерфейсы Java "сгенерированы", применяя сопоставление Java CORBA с IDL. Это сопоставление задается OMG... а не консорциумом W3. Поэтому создание "API-интерфейса, совместимого с Java 8 Stream" API-интерфейсов org.w3c.dom, приведет к тому, что OMG обновит сопоставление Java CORBA как Stream (что может быть проблематично с точки зрения совместимости CORBA, по крайней мере) или взломать соединение между API Java и CORBA.

К сожалению, выяснить, что (если что-либо) происходит в мире OMG при обновлении сопоставления IDL с Java, сложно... если вы не работаете в организации-члене OMG и т.д. Я этого не делаю.

Ответ 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;
}

Ответ 4

java8 Stream.iterate
Используйте так:

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