1

Stream<T> is based on internal iteration approach provided by Spliterator<T> which in turn delegates the iteration on boolean tryAdvance(Consumer<? super T> action) implementation. Put it simple:

Stream<T> ----> Spliterator<T> ----> boolean tryAdvance(Consumer<T>)

So, I would like to have some sort of utility that allows to create a Stream<T> from a Function<Consumer<T>, Boolean>. Note that Function<Consumer<T>, Boolean> has the same descriptor of boolean tryAdvance(Consumer<T>), i.e. Consumer<T> -> Boolean.

I am looking for an auxiliary function such as (updated according to @shmosel's comment):

static <T> Stream<T> stream(Predicate<Consumer<? super T>> moveNext) {
    Spliterator<T> iter = new AbstractSpliterator<T>(Long.MAX_VALUE, 0) {
        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            return moveNext.test(action);
        }
    };
    return StreamSupport.stream(iter, false);
}

This is the most concise way that I found to achieve that implementation. Yet, I still do not like the use of the anonymous inner class. Is there any simplest alternative?

Community
  • 1
  • 1
Miguel Gamboa
  • 8,855
  • 7
  • 47
  • 94
  • 1
    I don' know if that may be possible, but is there a reason for that requirement? Maybe what you want, may be achieved another way around. – João Rebelo Mar 24 '17 at 10:49
  • @JoãoRebelo There a many query methods that are not provided in original Stream API, such as `takeWhile`, `zip`, etc. So whenever you want to DIY and add a missing method you will have to work over `Iterator` or `Spliterator` and convert it back to `Stream` – Miguel Gamboa Mar 24 '17 at 10:53
  • e.g. [Limit a stream by a predicate](http://stackoverflow.com/q/20746429/1140754) or [How to skip even lines of a Stream](http://stackoverflow.com/q/30170089/1140754) – Miguel Gamboa Mar 24 '17 at 11:01
  • 2
    Wouldn't `Predicate` be more appropriate? (You can always use `func::get` to transform a `Function` to a `Predicate`.) – shmosel Mar 24 '17 at 16:33
  • @shmosel Yes you are right. I am going fix it. Thanks – Miguel Gamboa Mar 24 '17 at 16:40
  • 1
    Oops, I meant `func::apply`. – shmosel Mar 24 '17 at 16:43

1 Answers1

3

Since there is no builtin feature accepting a function, there is no way around creating a type, though it doesn’t have to be an inner class. E.g.

public interface SingleFuncStream<T> extends Spliterator<T> {
    public static <T> Stream<T> stream(SingleFuncStream<T> f) {
        return StreamSupport.stream(f, false);
    }
    @Override default public Spliterator<T> trySplit() { return null; }
    @Override default public long estimateSize() { return Long.MAX_VALUE; }
    @Override default public int characteristics() { return ORDERED; }
}

which can be used like,

ListIterator<String> i = Arrays.asList("foo", "bar", "baz").listIterator(3);
SingleFuncStream.<String>stream(c -> {
    if(!i.hasPrevious()) return false;
    c.accept(i.previous());
    return true;
}).forEach(System.out::println);

But now that you have clarified that you are aiming at implementing custom intermediate operations, the above solution isn’t suitable. It might be better to use the other alternative to an inner class, a dedicated top level class.

Most of these operations, like the examples you mentioned, do either, carry state or have to specify characteristics or a more sophisticated estimate size, which you can’t express using a single function.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Re: implementing custom intermediate operations: A static method that accepts lambdas that implement the methods in Spliterator can be used to implement said Spliterator, a la Collector::of. I do not know, however, if it would be better to design the lambdas Collector::of-style, with no ability to reference the resulting Spliterator, or to design said lambdas with the Spliterator instance as the first parameter. – srborlongan Mar 24 '17 at 11:32
  • 2
    @srborlongan: I already thought about it. For stateless ops, a `BiPredicate,Consumer super T>>` would be sufficient, but if you want to allow a state object to be passed, you need a function with three parameters, hence a custom interface. Letting the functions capture the spliterator instance reduces the parameters to two, but implies letting the functions repeat a lot of common work. – Holger Mar 24 '17 at 11:36
  • Agreed. I've used the custom interface solution, and it's quite fine. Not necessarily the first solution to come to mind, but it's in general better, if only because stateless lambdas are easier to create under that milieu. – srborlongan Mar 24 '17 at 11:40