Interface NodeStream<T extends Node>

  • Type Parameters:
    T - Type of nodes this stream contains. This parameter is covariant, which means for maximum flexibility, methods taking a node stream argument should declare it with an "extends" wildcard.
    All Superinterfaces:
    Iterable<@NonNull T>
    All Known Subinterfaces:
    NodeStream.DescendantNodeStream<T>

    public interface NodeStream<@NonNull T extends Node>
    extends Iterable<@NonNull T>
    A sequence of AST nodes. Conceptually similar to a Stream, and exposes a specialized API to navigate abstract syntax trees. This API can make it as easy as a XPath expression to navigate the tree.

    API usage

    The Node interface exposes methods like Node.children() or Node.asStream() to obtain new NodeStreams. Null-safe construction methods are available here, see of(Node), of(Node[]), fromIterable(Iterable).

    Most functions have an equivalent in the Stream interface and their behaviour is similar. One important departure from the Stream contract is the absence of requirement on the laziness of pipeline operations. More on that in the details section below.

    Some additional functions are provided to iterate the axes of the tree: children(), descendants(), descendantsOrSelf(), parents(), ancestors(), ancestorsOrSelf(), precedingSiblings(), followingSiblings(). Filtering and mapping nodes by type is possible through filterIs(Class), and the specialized children(Class), descendants(Class), and ancestors(Class).

    Many complex predicates about nodes can be expressed by testing the emptiness of a node stream. E.g. the following tests if the node is a variable declarator id initialized to the value 0:

         NodeStream.of(someNode)                    // the stream here is empty if the node is null
                   .filterIs(ASTVariableId.class)   // the stream here is empty if the node was not a variable declarator id
                   .followingSiblings()             // the stream here contains only the siblings, not the original node
                   .take(1)                         // the stream here contains only the first sibling, if it exists
                   .filterIs(ASTNumericLiteral.class)
                   .filter(it -> !it.isFloatingPoint() && it.getValueAsInt() == 0)
                   .nonEmpty(); // If the stream is non empty here, then all the pipeline matched
     

    Many existing operations from the node interface can be written with streams too:

    The new way to write those is as efficient as the old way.

    Unlike Streams, NodeStreams can be iterated multiple times. That means, that the operations that are terminal in the Stream interface (i.e. consume the stream) don't consume NodeStreams. Be aware though, that node streams don't cache their results by default, so e.g. calling count() followed by toList() will execute the whole pipeline twice. The elements of a stream can however be cached at an arbitrary point in the pipeline to evaluate the upstream only once. Some construction methods allow building a node stream from an external data source, e.g. fromIterable. Depending on how the data source is implemented, the built node streams may be iterable only once.

    Node streams may contain duplicates, which can be pruned with distinct().

    Details

    NodeStreams are not necessarily implemented with Stream, but when a method has an equivalent in the Stream API, their contract is similar. The only difference, is that node streams are not necessarily lazy, ie, a pipeline operation may be evaluated eagerly to improve performance. For this reason, relying on side-effects produced in the middle of the pipeline is a bad idea. Stream gives the same guideline about statefulness, but not for the same reason. Their justification is parallelism and operation reordering, once the pipeline is fully known.

    Node streams are meant to be sequential streams, so there is no equivalent to Stream.findAny(). The method first() is an equivalent to Stream.findFirst(). There is however a last() method, which may be implemented efficiently on some streams (eg children()).

    Node streams are most of the time ordered in document order (w.r.t. the XPath specification), a.k.a. prefix order. Some operations which explicitly manipulate the order of nodes, like union or append, may not preserve that ordering. map and flatMap operations may not preserve the ordering if the stream has more than one element, since the mapping is applied in order to each element of the receiver stream. This extends to methods defined in terms of map or flatMap, e.g. descendants() or children().

    Author:
    Clément Fournier
    Implementation Note:
    Choosing to wrap a stream instead of extending the interface is to allow the functions to return NodeStreams, and to avoid the code bloat induced by delegation.

    The default implementation relies on the iterator method. From benchmarking, that appears more efficient than streams.

    Since:
    7.0.0
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Interface Description
      static interface  NodeStream.DescendantNodeStream<T extends Node>
      A specialization of NodeStream that allows configuring tree traversal behaviour when traversing the descendants of a node.
    • Method Summary

      All Methods Static Methods Instance Methods Abstract Methods Default Methods 
      Modifier and Type Method Description
      boolean all​(Predicate<? super @NonNull T> predicate)
      Returns whether all elements of this stream match the provided predicate.
      default NodeStream<Node> ancestors()
      Returns a node stream containing all the ancestors of the nodes contained in this stream.
      default <R extends Node>
      NodeStream<R>
      ancestors​(Class<? extends R> rClass)
      Returns the ancestor stream of each node in this stream, filtered by the given node type.
      default NodeStream<Node> ancestorsOrSelf()
      Returns a node stream containing the nodes contained in this stream and their ancestors.
      boolean any​(Predicate<? super @NonNull T> predicate)
      Returns whether any elements of this stream match the provided predicate.
      NodeStream<T> append​(NodeStream<? extends @NonNull T> right)
      Returns a new node stream that contains all the elements of this stream, then all the elements of the given stream.
      static <O> Function<@Nullable Object,​@Nullable O> asInstanceOf​(Class<? extends O> c1, Class<? extends O>... rest)
      Returns a map function, that checks whether the parameter is an instance of any of the given classes.
      NodeStream<T> cached()
      Returns a node stream containing all the elements of this node stream, but which will evaluate the upstream pipeline only once.
      default NodeStream<Node> children()
      Returns a node stream containing all the children of the nodes contained in this stream.
      default <R extends Node>
      NodeStream<R>
      children​(Class<? extends R> rClass)
      Returns the children stream of each node in this stream, filtered by the given node type.
      <R,​A>
      R
      collect​(Collector<? super @NonNull T,​A,​R> collector)
      Collects the elements of this node stream using the specified Collector.
      int count()
      Returns the number of nodes in this stream.
      NodeStream.DescendantNodeStream<Node> descendants()
      Returns a node stream containing all the strict descendants of the nodes contained in this stream.
      <R extends Node>
      NodeStream.DescendantNodeStream<R>
      descendants​(Class<? extends R> rClass)
      Returns the descendant stream of each node in this stream, filtered by the given node type.
      NodeStream.DescendantNodeStream<Node> descendantsOrSelf()
      Returns a node stream containing the nodes contained in this stream and their descendants.
      NodeStream<T> distinct()
      Returns a stream consisting of the distinct elements (w.r.t Object.equals(Object)) of this stream.
      NodeStream<T> drop​(int n)
      Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
      NodeStream<T> dropLast​(int n)
      Returns a stream consisting of the elements of this stream except the n tail elements.
      static <T extends Node>
      NodeStream<T>
      empty()
      Returns an empty node stream.
      NodeStream<T> filter​(Predicate<? super @NonNull T> predicate)
      Returns a node stream consisting of the nodes of this stream that match the given predicate.
      default <R extends Node>
      NodeStream<R>
      filterIs​(Class<? extends R> rClass)
      Filters the nodes of this stream that are a subtype of the given class.
      default <U> NodeStream<T> filterMatching​(Function<? super @NonNull T,​? extends @Nullable U> extractor, U comparand)
      Filters the nodes of this stream by comparing a value extracted from the nodes with the given constant.
      default NodeStream<T> filterNot​(Predicate<? super @NonNull T> predicate)
      Filters the node of this stream using the negation of the given predicate.
      default <U> NodeStream<T> filterNotMatching​(Function<? super @NonNull T,​? extends @Nullable U> extractor, U comparand)
      @Nullable T first()
      Returns the first element of this stream, or null if the stream is empty.
      default <R extends Node>
      @Nullable R
      first​(Class<? extends R> rClass)
      Returns the first element of this stream of the given type, or null if there is none.
      default @Nullable T first​(Predicate<? super @NonNull T> predicate)
      Returns the first element of this stream that matches the given predicate, or null if there is none.
      default <R extends Node>
      NodeStream<R>
      firstChild​(Class<? extends R> rClass)
      Returns a stream containing the first child of each of the nodes in this stream that has the given type.
      default <R extends Node>
      @Nullable R
      firstNonNull​(Function<? super @NonNull T,​? extends @Nullable R> nullableFun)
      Returns the first element of this stream for which the mapping function returns a non-null result.
      default Optional<T> firstOpt()
      Returns an optional containing the first element of this stream, or an empty optional if the stream is empty.
      default @NonNull T firstOrThrow()
      Returns the first element of this stream, or throws a NoSuchElementException if the stream is empty.
      <R extends Node>
      NodeStream<R>
      flatMap​(Function<? super @NonNull T,​? extends @Nullable NodeStream<? extends R>> mapper)
      Returns a node stream consisting of the results of replacing each node of this stream with the contents of a stream produced by the given mapping function.
      default NodeStream<Node> followingSiblings()
      Returns a node stream containing all the following siblings of the nodes contained in this stream.
      void forEach​(Consumer<? super @NonNull T> action)  
      static <T extends Node,​R extends Node>
      NodeStream<R>
      forkJoin​(NodeStream<? extends T> upstream, Function<? super @NonNull T,​? extends NodeStream<? extends R>> fst, Function<? super @NonNull T,​? extends NodeStream<? extends R>> snd, Function<? super @NonNull T,​? extends NodeStream<? extends R>>... rest)
      Applies the given mapping functions to the given upstream in order and merges the results into a new node stream.
      static <T extends Node>
      NodeStream<T>
      fromIterable​(Iterable<? extends @Nullable T> iterable)
      Returns a new node stream that contains the same elements as the given iterable.
      default @Nullable T get​(int n)
      Returns the element at index n in this stream.
      default boolean isEmpty()
      Returns 'true' if the stream has no elements.
      @Nullable T last()
      Returns the last element of this stream, or null if the stream is empty.
      default <R extends Node>
      @Nullable R
      last​(Class<? extends R> rClass)
      Returns the last element of this stream of the given type, or null if there is none.
      <R extends Node>
      NodeStream<R>
      map​(Function<? super @NonNull T,​? extends @Nullable R> mapper)
      Returns a node stream consisting of the results of applying the given mapping function to the node of this stream.
      boolean none​(Predicate<? super @NonNull T> predicate)
      Returns whether no elements of this stream match the provided predicate.
      boolean nonEmpty()
      Returns 'true' if the stream has at least one element.
      static <T extends Node>
      NodeStream<T>
      of​(@Nullable T node)
      Returns a node stream containing zero or one node, depending on whether the argument is null or not.
      static <T extends Node>
      NodeStream<T>
      of​(T... nodes)
      Returns a node stream whose elements are the given nodes in order.
      static <T extends Node>
      NodeStream<T>
      ofOptional​(Optional<? extends T> optNode)
      Returns a node stream containing zero or one node, depending on whether the optional is empty or not.
      default NodeStream<Node> parents()
      Returns a node stream containing all the (first-degree) parents of the nodes contained in this stream.
      NodeStream<T> peek​(Consumer<? super @NonNull T> action)
      Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
      default NodeStream<Node> precedingSiblings()
      Returns a node stream containing all the preceding siblings of the nodes contained in this stream.
      NodeStream<T> prepend​(NodeStream<? extends @NonNull T> right)
      Returns a new node stream that contains all the elements of the given stream, then all the elements of this stream.
      default <R> R reduce​(R identity, BiFunction<? super R,​? super @NonNull T,​? extends R> accumulate)
      Reduce the elements of this stream sequentially.
      default int sumBy​(ToIntFunction<? super @NonNull T> toInt)
      Sum the elements of this stream by associating them to an integer.
      default int sumByInt​(ToIntFunction<? super @NonNull T> intMapper)
      Returns the sum of the value of the function applied to all elements of this stream.
      NodeStream<T> take​(int maxSize)
      Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
      NodeStream<T> takeWhile​(Predicate<? super @NonNull T> predicate)
      Returns the longest prefix of elements that satisfy the given predicate.
      default List<T> toList()
      Collects the elements of this node stream into a list.
      default <R> List<R> toList​(Function<? super @NonNull T,​? extends R> mapper)
      Maps the elements of this node stream using the given mapping and collects the results into a list.
      Stream<@NonNull T> toStream()
      Returns a new stream of Ts having the pipeline of operations defined by this node stream.
      static <T extends Node>
      NodeStream<T>
      union​(Iterable<? extends NodeStream<? extends T>> streams)
      Returns a node stream containing all the elements of the given streams, one after the other.
      static <T extends Node>
      NodeStream<T>
      union​(NodeStream<? extends T>... streams)
      Returns a node stream containing all the elements of the given streams, one after the other.
    • Method Detail

      • flatMap

        <R extends NodeNodeStream<R> flatMap​(Function<? super @NonNull T,​? extends @Nullable NodeStream<? extends R>> mapper)
        Returns a node stream consisting of the results of replacing each node of this stream with the contents of a stream produced by the given mapping function. If a mapped stream is null, it is discarded.

        If you want to flatMap this node stream to a Stream with arbitrary elements (ie not nodes), use toStream() then Stream.flatMap(Function).

        Type Parameters:
        R - Type of nodes contained in the returned stream
        Parameters:
        mapper - A function mapping the elements of this stream to another stream
        Returns:
        A flat mapped stream
        See Also:
        Stream.flatMap(Function)
      • map

        <R extends NodeNodeStream<R> map​(Function<? super @NonNull T,​? extends @Nullable R> mapper)
        Returns a node stream consisting of the results of applying the given mapping function to the node of this stream. If the mapping function returns null, the elements are not included.

        If you want to map this node stream to a Stream with arbitrary elements (ie not nodes), use toStream() then Stream.map(Function).

        Type Parameters:
        R - The node type of the new stream
        Parameters:
        mapper - A function mapping the elements of this stream to another node type
        Returns:
        A mapped stream
        See Also:
        Stream.map(Function)
      • peek

        NodeStream<T> peek​(Consumer<? super @NonNull T> action)
        Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream. Note that terminal operations such as count() don't necessarily execute the action.
        Parameters:
        action - an action to perform on the elements as they are consumed from the stream
        Returns:
        A new stream
      • append

        NodeStream<T> append​(NodeStream<? extends @NonNull T> right)
        Returns a new node stream that contains all the elements of this stream, then all the elements of the given stream.
        Parameters:
        right - Other stream
        Returns:
        A concatenated stream
        See Also:
        union(NodeStream[])
      • prepend

        NodeStream<T> prepend​(NodeStream<? extends @NonNull T> right)
        Returns a new node stream that contains all the elements of the given stream, then all the elements of this stream.
        Parameters:
        right - Other stream
        Returns:
        A concatenated stream
        See Also:
        union(NodeStream[])
      • cached

        NodeStream<T> cached()
        Returns a node stream containing all the elements of this node stream, but which will evaluate the upstream pipeline only once. The returned stream is not necessarily lazy, which means it may evaluate the upstream pipeline as soon as the call to this method is made.

        This is useful e.g. if you want to call several terminal operations without executing the pipeline several times. For example,

        
             NodeStream<T> stream = NodeStream.of(...)
                                              // long pipeline
                                              // ...
                                              .cached()
                                              // downstream
                                              // ...
                                              ;
        
             stream.forEach(this::addViolation); // both up- and downstream will be evaluated
             curViolations += stream.count();    // only downstream is evaluated
         
        Returns:
        A cached node stream
      • take

        NodeStream<T> take​(int maxSize)
        Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
        Parameters:
        maxSize - Maximum size of the returned stream
        Returns:
        A new node stream
        Throws:
        IllegalArgumentException - if n is negative
        See Also:
        Stream.limit(long), drop(int)
      • drop

        NodeStream<T> drop​(int n)
        Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned.
        Parameters:
        n - the number of leading elements to skip
        Returns:
        A new node stream
        Throws:
        IllegalArgumentException - if n is negative
        See Also:
        Stream.skip(long), take(int), dropLast(int)
      • dropLast

        NodeStream<T> dropLast​(int n)
        Returns a stream consisting of the elements of this stream except the n tail elements. If n is greater than the number of elements of this stream, returns an empty stream. This requires a lookahead buffer in general.
        Parameters:
        n - the number of trailing elements to skip
        Returns:
        A new node stream
        Throws:
        IllegalArgumentException - if n is negative
        See Also:
        drop(int)
      • takeWhile

        NodeStream<T> takeWhile​(Predicate<? super @NonNull T> predicate)
        Returns the longest prefix of elements that satisfy the given predicate.
        Parameters:
        predicate - The predicate used to test elements.
        Returns:
        the longest prefix of this stream whose elements all satisfy the predicate.
      • distinct

        NodeStream<T> distinct()
        Returns a stream consisting of the distinct elements (w.r.t Object.equals(Object)) of this stream.
        Returns:
        a stream consisting of the distinct elements of this stream
      • ancestors

        default NodeStream<Node> ancestors()
        Returns a node stream containing all the ancestors of the nodes contained in this stream. The returned stream doesn't preserve document order, since ancestors are yielded in innermost to outermost order.

        This is equivalent to flatMap(Node::ancestors).

        Returns:
        A stream of ancestors
        See Also:
        Node.ancestors(), ancestorsOrSelf(), ancestors(Class)
      • ancestorsOrSelf

        default NodeStream<Node> ancestorsOrSelf()
        Returns a node stream containing the nodes contained in this stream and their ancestors. The nodes of the returned stream are yielded in a depth-first fashion.

        This is equivalent to flatMap(Node::ancestorsOrSelf).

        Returns:
        A stream of ancestors
        See Also:
        ancestors()
      • parents

        default NodeStream<Node> parents()
        Returns a node stream containing all the (first-degree) parents of the nodes contained in this stream.

        This is equivalent to map(Node::getParent).

        Returns:
        A stream of parents
        See Also:
        ancestors(), ancestorsOrSelf()
      • children

        default NodeStream<Node> children()
        Returns a node stream containing all the children of the nodes contained in this stream.

        This is equivalent to flatMap(Node::children).

        Returns:
        A stream of children
        See Also:
        Node.children(), children(Class)
      • followingSiblings

        default NodeStream<Node> followingSiblings()
        Returns a node stream containing all the following siblings of the nodes contained in this stream.
        Returns:
        A stream of siblings
      • precedingSiblings

        default NodeStream<Node> precedingSiblings()
        Returns a node stream containing all the preceding siblings of the nodes contained in this stream. The nodes are yielded from left to right, i.e. in document order.
        Returns:
        A stream of siblings
      • children

        default <R extends NodeNodeStream<R> children​(Class<? extends R> rClass)
        Returns the children stream of each node in this stream, filtered by the given node type.

        This is equivalent to children().filterIs(rClass).

        Type Parameters:
        R - Type of node the returned stream should contain
        Parameters:
        rClass - Type of node the returned stream should contain
        Returns:
        A new node stream
        See Also:
        filterIs(Class), Node.children(Class)
      • firstChild

        default <R extends NodeNodeStream<R> firstChild​(Class<? extends R> rClass)
        Returns a stream containing the first child of each of the nodes in this stream that has the given type.

        This is equivalent to flatMap(it -> it.children(rClass).take(1)).

        Type Parameters:
        R - Type of node the returned stream should contain
        Parameters:
        rClass - Type of node the returned stream should contain
        Returns:
        A new node stream
        See Also:
        Node.children(Class)
      • ancestors

        default <R extends NodeNodeStream<R> ancestors​(Class<? extends R> rClass)
        Returns the ancestor stream of each node in this stream, filtered by the given node type.

        This is equivalent to ancestors().filterIs(rClass).

        Type Parameters:
        R - Type of node the returned stream should contain
        Parameters:
        rClass - Type of node the returned stream should contain
        Returns:
        A new node stream
        See Also:
        filterIs(Class), Node.ancestors(Class)
      • filterNot

        default NodeStream<T> filterNot​(Predicate<? super @NonNull T> predicate)
        Filters the node of this stream using the negation of the given predicate.

        This is equivalent to filter(predicate.negate())

        Parameters:
        predicate - A predicate to apply to each node to determine if it should be included
        Returns:
        A filtered node stream
        See Also:
        filter(Predicate)
      • filterMatching

        default <U> NodeStream<T> filterMatching​(Function<? super @NonNull T,​? extends @Nullable U> extractor,
                                                 U comparand)
        Filters the nodes of this stream by comparing a value extracted from the nodes with the given constant. This takes care of null value by calling Objects.equals(Object, Object). E.g. to filter nodes that have the image "a", use filterMatching(Node::getImage, "a").

        This is equivalent to filter(t -> Objects.equals(extractor.apply(t), comparand)).

        Type Parameters:
        U - Type of value to compare
        Parameters:
        extractor - Function extracting a value from the nodes of this stream
        comparand - Value to which the extracted value will be compared
        Returns:
        A filtered node stream
        See Also:
        filter(Predicate), filterNotMatching(Function, Object)
      • filterIs

        default <R extends NodeNodeStream<R> filterIs​(Class<? extends R> rClass)
        Filters the nodes of this stream that are a subtype of the given class.

        This is equivalent to filter(rClass::isInstance).map(rClass::cast).

        Type Parameters:
        R - The type of the nodes of the returned stream
        Parameters:
        rClass - The type of the nodes of the returned stream
        Returns:
        A filtered node stream
        See Also:
        filter(Predicate), asInstanceOf(Class, Class[])
      • reduce

        default <R> R reduce​(R identity,
                             BiFunction<? super R,​? super @NonNull T,​? extends R> accumulate)
        Reduce the elements of this stream sequentially.
        Type Parameters:
        R - Result type
        Parameters:
        identity - Identity element
        accumulate - Combine an intermediate result with a new node from this stream, returns the next intermediate result
        Returns:
        The last intermediate result (identity if this stream is empty)
      • sumBy

        default int sumBy​(ToIntFunction<? super @NonNull T> toInt)
        Sum the elements of this stream by associating them to an integer.
        Parameters:
        toInt - Map an element to an integer, which will be added to the running sum returns the next intermediate result
        Returns:
        The sum, zero if the stream is empty.
      • count

        int count()
        Returns the number of nodes in this stream.
        Returns:
        the number of nodes in this stream
      • sumByInt

        default int sumByInt​(ToIntFunction<? super @NonNull T> intMapper)
        Returns the sum of the value of the function applied to all elements of this stream.
        Parameters:
        intMapper - Mapping function
        Returns:
        The sum
      • nonEmpty

        boolean nonEmpty()
        Returns 'true' if the stream has at least one element.
        Returns:
        'true' if the stream has at least one element.
        See Also:
        isEmpty()
      • isEmpty

        default boolean isEmpty()
        Returns 'true' if the stream has no elements.
        Returns:
        'true' if the stream has no elements.
        See Also:
        nonEmpty()
      • any

        boolean any​(Predicate<? super @NonNull T> predicate)
        Returns whether any elements of this stream match the provided predicate. If the stream is empty then false is returned and the predicate is not evaluated.
        Parameters:
        predicate - The predicate that one element should match for this method to return true
        Returns:
        true if any elements of the stream match the provided predicate, otherwise false
        See Also:
        all(Predicate), none(Predicate)
      • none

        boolean none​(Predicate<? super @NonNull T> predicate)
        Returns whether no elements of this stream match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated.
        Parameters:
        predicate - The predicate that no element should match for this method to return true
        Returns:
        true if either no elements of the stream match the provided predicate or the stream is empty, otherwise false
        See Also:
        any(Predicate), all(Predicate)
      • all

        boolean all​(Predicate<? super @NonNull T> predicate)
        Returns whether all elements of this stream match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated.
        Parameters:
        predicate - The predicate that all elements should match for this method to return true
        Returns:
        true if either all elements of the stream match the provided predicate or the stream is empty, otherwise false
        See Also:
        any(Predicate), none(Predicate)
      • get

        default @Nullable T get​(int n)
        Returns the element at index n in this stream. If no such element exists, null is returned.

        This is equivalent to drop(n).first().

        If you'd rather continue processing the nth element as a node stream, you can use drop(n).take(1).

        Parameters:
        n - Index of the element to find
        Returns:
        The nth element of this stream, or null if it doesn't exist
        Throws:
        IllegalArgumentException - if n is negative
      • first

        @Nullable T first()
        Returns the first element of this stream, or null if the stream is empty.

        If you'd rather continue processing the first element as a node stream, you can use take(1).

        This is equivalent to get(0).

        Returns:
        the first element of this stream, or null if it doesn't exist
        See Also:
        first(Predicate), first(Class), firstOpt()
      • firstOpt

        default Optional<T> firstOpt()
        Returns an optional containing the first element of this stream, or an empty optional if the stream is empty.

        This is equivalent to Optional.ofNullable(first()).

        Returns:
        the first element of this stream, or an empty optional if it doesn't exist
        See Also:
        first(Predicate), first(Class), first()
      • first

        default @Nullable T first​(Predicate<? super @NonNull T> predicate)
        Returns the first element of this stream that matches the given predicate, or null if there is none.
        Parameters:
        predicate - The predicate that one element should match for this method to return it
        Returns:
        the first element of this stream that matches the given predicate, or null if it doesn't exist
        See Also:
        first(), first(Class)
      • first

        default <R extends Node> @Nullable R first​(Class<? extends R> rClass)
        Returns the first element of this stream of the given type, or null if there is none.
        Type Parameters:
        R - The type of node to find
        Parameters:
        rClass - The type of node to find
        Returns:
        the first element of this stream of the given type, or null if it doesn't exist
        See Also:
        first(), first(Predicate)
      • firstNonNull

        default <R extends Node> @Nullable R firstNonNull​(Function<? super @NonNull T,​? extends @Nullable R> nullableFun)
        Returns the first element of this stream for which the mapping function returns a non-null result. Returns null if there is no such element. This is a convenience method to use with asInstanceOf(Class, Class[]), because using just map followed by first() will lose the type information and mentioning explicit type arguments would be needed.
        Type Parameters:
        R - Result type
        Parameters:
        nullableFun - Mapper function
        Returns:
        A node, or null
        See Also:
        asInstanceOf(Class, Class[])
      • last

        @Nullable T last()
        Returns the last element of this stream, or null if the stream is empty. This may or may not require traversing all the elements of the stream.
        Returns:
        the last element of this stream, or null if it doesn't exist
      • last

        default <R extends Node> @Nullable R last​(Class<? extends R> rClass)
        Returns the last element of this stream of the given type, or null if there is none.
        Type Parameters:
        R - The type of node to find
        Parameters:
        rClass - The type of node to find
        Returns:
        the last element of this stream of the given type, or null if it doesn't exist
        See Also:
        last()
      • toStream

        Stream<@NonNull T> toStream()
        Returns a new stream of Ts having the pipeline of operations defined by this node stream. This can be called multiple times.
        Returns:
        A stream containing the same elements as this node stream
      • toList

        default List<T> toList()
        Collects the elements of this node stream into a list. Just like for Collectors.toList(), there are no guarantees on the type, mutability, serializability, or thread-safety of the returned list.

        This is equivalent to collect(Collectors.toList()).

        Returns:
        a list containing the elements of this stream
        See Also:
        Collectors.toList(), collect(Collector)
      • toList

        default <R> List<R> toList​(Function<? super @NonNull T,​? extends R> mapper)
        Maps the elements of this node stream using the given mapping and collects the results into a list.

        This is equivalent to collect(Collectors.mapping(mapper, Collectors.toList())).

        Type Parameters:
        R - Return type of the mapper, and element type of the returned list
        Parameters:
        mapper - Mapping function
        Returns:
        a list containing the elements of this stream
        See Also:
        Collectors.mapping(Function, Collector), collect(Collector)
      • of

        static <T extends NodeNodeStream<T> of​(@Nullable T node)
        Returns a node stream containing zero or one node, depending on whether the argument is null or not.

        If you know the node is not null, you can also call node.asStream().

        Type Parameters:
        T - Element type of the returned stream
        Parameters:
        node - The node to contain
        Returns:
        A new node stream
        See Also:
        Node.asStream()
      • fromIterable

        static <T extends NodeNodeStream<T> fromIterable​(Iterable<? extends @Nullable T> iterable)
        Returns a new node stream that contains the same elements as the given iterable. Null items are filtered out of the resulting stream.

        It's possible to map an iterator to a node stream by calling fromIterable(() -> iterator), but then the returned node stream would only be iterable once.

        Type Parameters:
        T - Type of nodes in the returned node stream
        Parameters:
        iterable - Source of nodes
        Returns:
        A new node stream
      • ofOptional

        static <T extends NodeNodeStream<T> ofOptional​(Optional<? extends T> optNode)
        Returns a node stream containing zero or one node, depending on whether the optional is empty or not.
        Type Parameters:
        T - Element type of the returned stream
        Parameters:
        optNode - The node to contain
        Returns:
        A new node stream
        See Also:
        of(Node)
      • of

        @SafeVarargs
        static <T extends NodeNodeStream<T> of​(T... nodes)
        Returns a node stream whose elements are the given nodes in order. Null elements are not part of the resulting node stream.
        Type Parameters:
        T - Element type of the returned stream
        Parameters:
        nodes - The elements of the new stream
        Returns:
        A new node stream
      • union

        @SafeVarargs
        static <T extends NodeNodeStream<T> union​(NodeStream<? extends T>... streams)
        Returns a node stream containing all the elements of the given streams, one after the other.
        Type Parameters:
        T - The type of stream elements
        Parameters:
        streams - the streams to flatten
        Returns:
        the concatenation of the input streams
      • union

        static <T extends NodeNodeStream<T> union​(Iterable<? extends NodeStream<? extends T>> streams)
        Returns a node stream containing all the elements of the given streams, one after the other.
        Type Parameters:
        T - The type of stream elements
        Parameters:
        streams - the streams to flatten
        Returns:
        the concatenation of the input streams
      • empty

        static <T extends NodeNodeStream<T> empty()
        Returns an empty node stream.
        Type Parameters:
        T - Expected type of nodes.
        Returns:
        An empty node stream
      • forkJoin

        @SafeVarargs
        static <T extends Node,​R extends NodeNodeStream<R> forkJoin​(NodeStream<? extends T> upstream,
                                                                            Function<? super @NonNull T,​? extends NodeStream<? extends R>> fst,
                                                                            Function<? super @NonNull T,​? extends NodeStream<? extends R>> snd,
                                                                            Function<? super @NonNull T,​? extends NodeStream<? extends R>>... rest)
        Applies the given mapping functions to the given upstream in order and merges the results into a new node stream. This allows exploring several paths at once on the same stream. The method is lazy and won't evaluate the upstream pipeline several times.
        Type Parameters:
        R - Common supertype for the element type of the streams returned by the mapping functions
        Parameters:
        upstream - Source of the stream
        fst - First mapper
        snd - Second mapper
        rest - Rest of the mappers
        Returns:
        A merged node stream
      • asInstanceOf

        @SafeVarargs
        static <O> Function<@Nullable Object,​@Nullable O> asInstanceOf​(Class<? extends O> c1,
                                                                             Class<? extends O>... rest)
        Returns a map function, that checks whether the parameter is an instance of any of the given classes. If so, it returns the parameter, otherwise it returns null.

        This may be used to filter a node stream to those specific classes, for example:

        
             NodeStream<ASTExpression> exprs = someStream.map(asInstanceOf(ASTInfixExpression.class, ASTCastExpression.class));
         
        Using this in the middle of a call chain might require passing explicit type arguments:
        
            ASTTypeDeclaration ts =
               node.ancestors()
                   .<ASTTypeDeclaration>map(asInstanceOf(ASTClassDeclaration.class, ASTEnumDeclaration.class))
                   .first(); // would not compile without the explicit type arguments
         

        For this use case the firstNonNull(Function) method may be used, which reduces the above to

        
            ASTTypeDeclaration ts =
               node.ancestors().firstNonNull(asInstanceOf(ASTClassDeclaration.class, ASTEnumDeclaration.class));
         
        Type Parameters:
        O - Output type
        Parameters:
        c1 - First type to test
        rest - Other types to test
        See Also:
        firstNonNull(Function)