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 
    A specialization of NodeStream that allows configuring tree traversal behaviour when traversing the descendants of a node.
  • Method Summary

    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>
    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>
    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.
    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.
    Returns a node stream containing all the elements of this node stream, but which will evaluate the upstream pipeline only once.
    default NodeStream<Node>
    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
    Returns the number of nodes in this stream.
    Returns a node stream containing all the strict descendants of the nodes contained in this stream.
    descendants(Class<? extends R> rClass)
    Returns the descendant stream of each node in this stream, filtered by the given node type.
    Returns a node stream containing the nodes contained in this stream and their descendants.
    Returns a stream consisting of the distinct elements (w.r.t Object.equals(Object)) of this stream.
    drop(int n)
    Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream.
    dropLast(int n)
    Returns a stream consisting of the elements of this stream except the n tail elements.
    static <T extends Node>
    NodeStream<T>
    Returns an empty node stream.
    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
    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>
    Returns an optional containing the first element of this stream, or an empty optional if the stream is empty.
    default @NonNull T
    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>
    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
    Returns 'true' if the stream has no elements.
    @Nullable T
    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
    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>
    Returns a node stream containing all the (first-degree) parents of the nodes contained in this stream.
    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>
    Returns a node stream containing all the preceding siblings of the nodes contained in this stream.
    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.
    take(int maxSize)
    Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
    takeWhile(Predicate<? super @NonNull T> predicate)
    Returns the longest prefix of elements that satisfy the given predicate.
    default List<T>
    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>
    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.

    Methods inherited from interface java.lang.Iterable

    iterator, spliterator
  • Method Details

    • flatMap

      <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. 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:
    • map

      <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. 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:
    • filter

      NodeStream<T> filter(Predicate<? super @NonNull T> predicate)
      Returns a node stream consisting of the nodes of this stream that match the given predicate.
      Parameters:
      predicate - A predicate to apply to each node to determine if it should be included
      Returns:
      A filtered node stream
      See Also:
    • 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:
    • 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:
    • 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:
    • 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:
    • 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:
    • 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:
    • 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:
    • 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:
    • 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:
    • descendants

      Returns a node stream containing all the strict descendants of the nodes contained in this stream. See NodeStream.DescendantNodeStream for details.

      This is equivalent to flatMap(Node::descendants), except the returned stream is a NodeStream.DescendantNodeStream.

      Returns:
      A stream of descendants
      See Also:
    • descendantsOrSelf

      Returns a node stream containing the nodes contained in this stream and their descendants. See NodeStream.DescendantNodeStream for details.

      This is equivalent to flatMap(Node::descendantsOrSelf), except the returned stream is a NodeStream.DescendantNodeStream.

      Returns:
      A stream of descendants
      See Also:
    • 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 Node> NodeStream<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:
    • firstChild

      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.

      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:
    • descendants

      <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. See NodeStream.DescendantNodeStream for details.

      This is equivalent to descendants().filterIs(rClass), except the returned stream is a NodeStream.DescendantNodeStream.

      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:
    • ancestors

      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.

      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:
    • 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:
    • 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:
    • filterIs

      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.

      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:
    • filterNotMatching

      default <U> NodeStream<T> filterNotMatching(Function<? super @NonNull T,? extends @Nullable U> extractor, U 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:
    • forEach

      void forEach(Consumer<? super @NonNull T> action)
      Specified by:
      forEach in interface Iterable<T extends Node>
    • 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

      default boolean isEmpty()
      Returns 'true' if the stream has no elements.
      Returns:
      'true' if the stream has no elements.
      See Also:
    • 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:
    • 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:
    • 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:
    • 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:
    • firstOrThrow

      default @NonNull T firstOrThrow()
      Returns the first element of this stream, or throws a NoSuchElementException if the stream is empty.
      Returns:
      the first element of this stream
      See Also:
    • 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

      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

      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:
    • 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:
    • 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:
    • collect

      <R, A> R collect(Collector<? super @NonNull T,A,R> collector)
      Collects the elements of this node stream using the specified Collector. This is equivalent to toStream() followed by Stream.collect(Collector).
      Type Parameters:
      R - the type of the result
      A - the intermediate accumulation type of the Collector
      Parameters:
      collector - the Collector describing the reduction
      Returns:
      the result of the reduction
      See Also:
    • 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:
    • 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:
    • of

      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.

      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:
    • fromIterable

      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. 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 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.
      Type Parameters:
      T - Element type of the returned stream
      Parameters:
      optNode - The node to contain
      Returns:
      A new node stream
      See Also:
    • of

      @SafeVarargs static <T extends Node> NodeStream<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 Node> NodeStream<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 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.
      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 Node> NodeStream<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 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. 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: