1

My understanding is this ask of mine is NOT possible in a straight forward way. but I want to find a solution that works.

Here is how I get an Iterable for NamedNodeMap(javax package);

private static Iterable<Node> iterableNamedNodeMap(NamedNodeMap namedNodeMap) {
        return () -> new Iterator<Node>() {

            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < namedNodeMap.getLength();
            }

            @Override
            public Node next() {
                if (!hasNext())
                    throw new NoSuchElementException();
                return namedNodeMap.item(index++);
            }
        };
}

And here is the iterable for NodeList(javax)

 private static Iterable<Node> iterableNamedNodeMap(NodeList nodeList) {
            return () -> new Iterator<Node>() {

                private int index = 0;

                @Override
                public boolean hasNext() {
                    return index < nodeList.getLength();
                }

                @Override
                public Node next() {
                    if (!hasNext())
                        throw new NoSuchElementException();
                    return nodeList.item(index++);
                }
            };
    }

Since they are pretty much identical except for the parameters, I was hoping for something like this, which of-course is not right. Both NodeList and NamedNodeMap does not implement a common interface. so what is the best way to do here.

private static <T extends NodeList | NamedNodeMap> Iterable<Node> iterableNamedNodeMap(T in) {
        return () -> new Iterator<Node>() {

            private int index = 0;

            @Override
            public boolean hasNext() {
                return index < in.getLength();
            }

            @Override
            public Node next() {
                if (!hasNext())
                    throw new NoSuchElementException();
                return in.item(index++);
            }
        };
brain storm
  • 30,124
  • 69
  • 225
  • 393
  • take a look at this answer https://stackoverflow.com/a/745769/8112217 – tsarenkotxt Jun 18 '19 at 01:16
  • 1
    Thats a different concept, showing a generic bound which is a union of the two interfaces. This question is asking about providing a generic method for alternative interfaces, which to my knowledge is not possible. – flakes Jun 18 '19 at 01:20

1 Answers1

1

You could reduce some of the boilerplate by creating a factory method that accepts two functional interfaces, taken from NodeList or NamedNodeMap using method references:

private static Iterable<Node> iterableNodes(
    Supplier<int> lengthGetter,
    Function<int, Node> itemGetter
) {
     return () -> new Iterator<Node>() {
        private int index = 0;

        @Override
        public boolean hasNext() {
            return index < lengthGetter.get();
        }

        @Override
        public Node next() {
            if (!hasNext())
                throw new NoSuchElementException();
            return itemGetter.apply(index++);
        }
    };
}

private static Iterable<Node> iterableNamedNodeMap(NamedNodeMap namedNodeMap) {
    return iterableNodes(namedNodeMap::getLength, namedNodeMap::item);
}

private static Iterable<Node> iterableNodeList(NodeList nodeList) {
    return iterableNodes(nodeList::getLength, nodeList::item);
}
flakes
  • 21,558
  • 8
  • 41
  • 88
  • 1
    Interesting solution! – brain storm Jun 18 '19 at 01:19
  • 1
    @brainstorm the nice thing about this pattern is that it adds a lot of flexibility for new types to be added, you don't need to update any existing method to allow new `iterable*` methods to be created. You could even make the `Node` class in `iterableNodes` as a generic parameter to make the solution even more flexible. ` Iterable iterableItems(...)` – flakes Jun 18 '19 at 01:25