Inclusive takeWhile() for Streams

大憨熊 提交于 2020-02-02 15:44:46

问题


I want to know if there is a way to add the last element of the stream that was tested against the condition of the method takeWhile(). I believe I want to achieve something similar to RxJava's takeUntil() method.

I'm guessing there is no direct way to do this (correct me if I am mistaken), but I would like to know if there is a proper workaround to achieve this that I am now aware of.

I've searched throughout Stackoverflow with little to no success. If you think there are threads that could solve my problems, I would certainly like to see it.

If you look at the following code's peek() you will see that the number 5 is checked against the takeWhile() condition but it never arrives in the forEach():

IntStream.of(1, 3, 2, 5, 4, 6)
        .peek(foo -> System.out.println("Peek: " + foo))
        .takeWhile(n -> n < 5)
        .forEach(bar -> System.out.println("forEach: " + bar));

The expected result is for the last element checked against takeWhile's condition to arrive at the forEach's System.out::println. In this case it is 5.

Thanks to everyone!


回答1:


There's no convenient way to do that with the normal stream API. It is possible in an ugly way (you would need to adapt this implementation, that's just a normal takeWhile "backported" for Java 8).

This guy has written a stream extension library which has takeWhileInclusive.

Sample usage:

IntStreamEx.of(1, 3, 2, 5, 4, 6)
    .peek(foo -> System.out.println("Peek: " + foo))
    .takeWhileInclusive(n -> n < 5)
    .forEach(bar -> System.out.println("forEach: " + bar));



回答2:


I add an horrible approach that might be overkill for your (or any) use case, but just for fun.

public static void main(String[] args) {
    List<Integer> source = List.of(1, 3, 2, 5, 4, 6);
    Iterator<Integer> iterator = source.iterator();
    AtomicBoolean proceed = new AtomicBoolean(true);

    Stream
        .generate(() -> {
            if (!proceed.get() || !iterator.hasNext()) {
                return null;
            }
            int value = iterator.next();
            System.out.println("generate: " + value);
            proceed.set(value < 5);
            return value;
        })
        .takeWhile(Objects::nonNull)
        .forEach(bar -> System.out.println("forEach: " + bar));

}

The output will be:

generate: 1
forEach: 1
generate: 3
forEach: 3
generate: 2
forEach: 2
generate: 5
forEach: 5

Probably the worst thing about this approach is that it gives generate() a responsibility (checking if there are more) that it does not belong with it.



来源:https://stackoverflow.com/questions/55453144/inclusive-takewhile-for-streams

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!