Class HNLI<E extends HTMLNode>

  • Type Parameters:
    E - The type of HTMLNode being iterated.
    All Implemented Interfaces:
    java.util.Iterator<E>, java.util.ListIterator<E>

    public class HNLI<E extends HTMLNode>
    extends AbstractHNLI<E,​E>
    A Java Generic Iterator-Class that for iterating TagNode, TextNode and CommentNode instances which match user-provided search-criteria.

    This interface builds on Java's 'ListIterator<E>' interface.

    This is an Iterator class that has been heavily improved to allow for all types of updates, additions, removals, etc... to a vectorized-html web-page. The methods that are provided allow a user to request an Iterator from the three primary Iterator retrieval classes in this Node-Search Package.

    HNLI<E> (Iterator) Generator Classes:



    public interface java.util.Iterator<E> has these methods:

    • boolean hasNext()
    • default void forEachRemaining(Consumer<? super E> action)
    • E next()
    • default void remove()


    public interface java.util.ListIterator<E> extends the previous Iterator with these methods:

    • void add(E e)
    • boolean hasNext()
    • boolean hasPrevious()
    • E next()
    • int nextIndex()
    • E previous()
    • int previousIndex()
    • void remove()
    • void set(E e)


    NOTE: This Iterator class further extends Java's ListIterator<E> to add several HTMLNode and Vector<HTMLNode> specific insertion, deletion, and replacement operations. These methods are listed below in the 'Methods' section of this class documentation page.

    THE WISDOM OF AN ITERATOR: Generally, it is sometimes apparent that Java's introduction of the concept of generics - and particularly the Iterator<E> and ListIterator<E> has been somewhat down-played in some circles. The value of an Iterator is sometimes over-looked when applied to data-modification. 4 out of 6 of the static method-based class-types in this package: Find, Get, Peek, Count and Count provide only "data-observation" of the underlying vectorized-HTML. The other two Poll and Remove, however, modify the underlying Vector. All of these work fine without an using an Iterator, however, there may be cases where node-replacement and node-removal on a case-by-case basis will be necessary. And that can lead to problems caused by stale data pointers.

    STALE DATA POINTERS: If an array of index pointers is requested: int[] posArr = TagNodeFind.all(...) and the user begins replacing and removing nodes using this array... if at any point the size of the Vector is changed, the entire pointer-array will immediately contain stale-data! This can be overcome by maintaining a 'Vector-size delta' value, and offsetting each value in the pointer-array. Indeed, however, this is exactly what the HNLI and HNLIInclusive iterators do internally! If a programmer employs the set(...), add(...) and remove(...) methods provided by the Iterator-classes both in this package, and the java-interfaces they inherit, internally a size-delta and a cursor are maintained by the Iterator when & if elements are added, updated and removed. As long long as the underlying Vector is not modified by code outside of the Iterator methods, stale and invalid data-pointers will never be returned by the getter methods of this class. Index-Pointer Arrays are often useful, but less-so when the user plans on changing or adding sections of HTMLNode that change how many nodes are in the underlying Vector.


    • Method Detail

      • hasPrevious

        🡇    
        public boolean hasPrevious()
        Use this method to find out whether the underlying Vector and current cursor position would retrieve another match if 'previous()' or 'previousIndex()' were called.
        Returns:
        This shall return TRUE if calling the previous(), or previousIndex() methods would return another node-match. This method shall return FALSE if calling previous would generate / throw a 'NoSuchElementException' - because there are no more matches in the underlying Vector, given the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        Code:
        Exact Method Body:
         CHECK_CME();
        
         if (hasPrevVectorPos != -1) return true;
        
         Object o; // Temp Object
        
         int LOOP_BOUNDARY = (minCursor == -1) ? 0 : minCursor;
        
         if (cursor == -1) cursor = LOOP_BOUNDARY;  // will return false
        
         // System.out.println("Loop Boundary: " + LOOP_BOUNDARY + ", cursor: " + cursor);
        
         while (--cursor >= LOOP_BOUNDARY)
        
             if (c.isInstance(o = v.elementAt(cursor)) && p.test(c.cast(o)))
             {
                 hasPrevVectorPos = cursor;
                 return true;
             }
        
         return false;
        
      • previous

        🡅  🡇    
        public E previous()
        Returns the nearest node-match in the underlying Vector, given the current cursor position - when searching in the left-direction, or in the direction of decreasing Vector-indices.
        Returns:
        This shall return the node-match that is directly previous to the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        java.util.NoSuchElementException - If there aren't any more matches available, this exception shall throw. Avoid having to catch this exception by always calling method 'hasPrevious', and only invoking 'previous' if that method returned TRUE.
        Code:
        Exact Method Body:
         return (E) v.elementAt(previousIndex());
        
      • previousIndex

        🡅  🡇    
        public int previousIndex()
        Returns the nearest node-match, as an integer Vector-index, in the underlying Vector, given the current cursor position - when searching in the left-direction, or in the direction of decreasing Vector-indices.
        Returns:
        This shall return the node-match that is directly previous to the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        java.util.NoSuchElementException - If there aren't any more matches available, this exception shall throw. Avoid having to catch this exception by always calling method 'hasPrevious()', and only invoking 'previousIndex()' if that method returned TRUE.
        Code:
        Exact Method Body:
         CHECK_CME();
        
         int temp = hasPrevVectorPos;
        
         hasPrevVectorPos = hasNextVectorPos = -1;
         modifiedSince = false;
        
         if (temp != -1) return temp;
        
         Object o; // Temp Object
        
         int LOOP_BOUNDARY = (minCursor == -1) ? 0 : minCursor;
        
         if (cursor == -1) cursor = LOOP_BOUNDARY; // will throw exception
        
         while (--cursor >= LOOP_BOUNDARY)
        
             if (c.isInstance(o = v.elementAt(cursor)) && p.test(c.cast(o)))
                 return cursor;
        
         throw new NoSuchElementException("There are no more 'previous' elements available.");
        
      • hasNext

        🡅  🡇    
        public boolean hasNext()
        Use this method to find out whether the underlying Vector and current cursor position would retrieve another match if 'next()' or 'nextIndex()' were called.
        Returns:
        This shall return TRUE if calling the next(), or nextIndex() methods would return another node-match. This method shall return FALSE if calling next() would generate / throw a 'NoSuchElementException' - because there are no more matches in the underlying Vector, given the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        Code:
        Exact Method Body:
         CHECK_CME();
        
         if (hasNextVectorPos != -1) return true;
        
         Object o; // Temp Object
        
         int LOOP_BOUNDARY = (maxCursor == -1) ? (v.size() - 1) : maxCursor;
        
         if (cursor == -1) cursor = (minCursor == -1) ? -1 : (minCursor-1);
        
         // System.out.println("Loop Boundary: " + LOOP_BOUNDARY + ", cursor: " + cursor);
        
         while (++cursor <= LOOP_BOUNDARY)
        
             if (c.isInstance(o = v.elementAt(cursor)) && p.test(c.cast(o)))
                 { hasNextVectorPos=cursor;  return true; }
        
         return false;
        
      • next

        🡅  🡇    
        public E next()
        Returns the nearest node-match in the underlying Vector, given the current cursor position - when searching in the right-direction, or in the direction of increasing Vector-indices.
        Returns:
        This shall return the node-match that is directly next to the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        java.util.NoSuchElementException - If there aren't any more matches available, this exception shall throw. Avoid having to catch this exception by always calling method 'hasNext()', and only invoking 'next()' if that method returned TRUE.
        Code:
        Exact Method Body:
         return (E) v.elementAt(nextIndex());
        
      • nextIndex

        🡅  🡇    
        public int nextIndex()
        Returns the nearest node-match, as an integer Vector-index, in the underlying Vector, given the current cursor position - when searching in the right-direction, or in the direction of increasing Vector-indices.
        Returns:
        This shall return the node-match that is directly next to the current cursor position.
        Throws:
        java.util.ConcurrentModificationException - Internal to this Iterator's state, there is a private int 'expectedSize' maintained. If modifications are made to the underlying vectorized-html, from outside of the add(...), set(...) or remove(...) variants provided by this interface then the value of this internal-field int 'expectedSize' will not be consistent with the actual size of the Vector. When this situation arises, both class HNLI and also HNLIInclusive will throw a ConcurrentModificationException.

        NOTE: Changes to the underlying Vector that do not modify the size will simply not be detected. This is due to 'a bug' in the JDK implementation of AbstractList which keeps an integer-field named 'modCount' stored as 'protected' - and (unfortunately) unavailable to implementers of AbstractList (rendering it useless).

        ALSO: Any call made to a variant of the provided first(...) or last(...) methods will cause the internal int 'expected-size' field to reset. This would, therefore, prevent ConcurrentModificationException from throwing - even if code from outside the Iterator had modified the size of the underlying Vector.
        java.util.NoSuchElementException - If there aren't any more matches available, this exception shall throw. Avoid having to catch this exception by always calling method 'hasNext()', and only invoking 'nextIndex()' if that method returned TRUE.
        Code:
        Exact Method Body:
         CHECK_CME();
        
         int temp = hasNextVectorPos;
        
         hasPrevVectorPos = hasNextVectorPos = -1;
         modifiedSince = false;
        
         if (temp != -1) return temp;
        
         Object o; // Temp Object
        
         int LOOP_BOUNDARY = (maxCursor == -1) ? (v.size() - 1) : maxCursor;
        
         if (cursor == -1) cursor = (minCursor == -1) ? -1 : (minCursor-1);
        
         while (++cursor <= LOOP_BOUNDARY)
        
             if (c.isInstance(o = v.elementAt(cursor)) && p.test(c.cast(o)))
                 return cursor;
        
         throw new NoSuchElementException("There are no more 'next' elements available.");
        
      • first

        🡅  🡇    
        public E first()
        Convenience Method
        Invokes: firstIndex()
        Retrieves: 'E' node-instance from the Vector
        Code:
        Exact Method Body:
         return (E) v.elementAt(firstIndex());
        
      • firstIndex

        🡅  🡇    
        public int firstIndex()
        This method will "reset the internal cursor" to the beginning, and return the index of the first node-match (rather than the node itself).

        NOTE: This method is somewhat of a "reset method" - because the internal-cursor is moved to the beginning of the underlying-Vector. Whenever the cursor is moved (or restricted), the logic that checks for a ConcurrentModificationException is reset.

        In normal situations, when statements or method's from outside the update methods in this class, modify the underlying html-Vector a ConcurrentModificationException shall throw. However, whenever an HTML Node List Iterator method moves the cursor, the logic for checking Concurrent Modification will reset (by setting the internal 'expectedSize' field to v.size()). This shall prevent an exception throw if outside modification of the underlying Vector has occurred.
        Returns:
        The index of the very-first node-match in this list. As with other Iterator-retrieval methods, if the underlying Vector has been changed using calls to: set, remove, or add, then this method will return the first-integer index of the node-match for the modified-Vector.
        Code:
        Exact Method Body:
         cursor              = (minCursor == -1) ? 0 : minCursor;
         hasNextVectorPos    = hasPrevVectorPos = -1;
         expectedSize        = v.size();
                
         // NOTE: A call to first, last, firstIndex, or lastIndex
         // "resets" the CME Monitor-Logic ==> expectedSize = v.size();
        
         return nextIndex();
        
      • last

        🡅  🡇    
        public E last()
        Convenience Method
        Invokes: lastIndex()
        Retrieves: 'E' node-instance from the Vector
        Code:
        Exact Method Body:
         return (E) v.elementAt(lastIndex());
        
      • lastIndex

        🡅    
        public int lastIndex()
        This method will "advance the internal cursor" to the end of the Vector, and return the index of the last node-match (rather than the node itself).

        NOTE: This method is somewhat of a "reset method" - because the internal-cursor is moved to the beginning of the underlying-Vector. Whenever the cursor is moved (or restricted), the logic that checks for a ConcurrentModificationException is reset.

        In normal situations, when statements or method's from outside the update methods in this class, modify the underlying html-Vector a ConcurrentModificationException shall throw. However, whenever an HTML Node List Iterator method moves the cursor, the logic for checking Concurrent Modification will reset (by setting the internal 'expectedSize' field to v.size()). This shall prevent an exception throw if outside modification of the underlying Vector has occurred.
        Returns:
        The index of the very-last node-match in this list. As with other Iterator-retrieval methods, if the underlying Vector has been changed using calls to: set, remove, or add, then this method will return the last-integer index of the node-match for the modified-Vector.
        Code:
        Exact Method Body:
         cursor              = (maxCursor == -1) ? (v.size() - 1) : maxCursor;
         hasNextVectorPos    = hasPrevVectorPos = -1;
         expectedSize        = v.size();
        
         // NOTE: A call to first, last, firstIndex, or lastIndex
         // "resets" the CME Monitor-Logic ==> expectedSize = v.size();
        
         return previousIndex();