获取流最后一个元素的最有效方法

2022-08-31 12:41:45

流没有方法:last()

Stream<T> stream;
T last = stream.last(); // No such method

获取最后一个元素(或空流为空)的最优雅和/或最有效的方法是什么?


答案 1

执行一个仅返回当前值的缩减:

Stream<T> stream;
T last = stream.reduce((a, b) -> b).orElse(null);

答案 2

这在很大程度上取决于 的性质。请记住,“简单”并不一定意味着“高效”。如果您怀疑流非常大,承载了繁重的操作或具有事先知道大小的源,则以下方法可能比简单的解决方案更有效:Stream

static <T> T getLast(Stream<T> stream) {
    Spliterator<T> sp=stream.spliterator();
    if(sp.hasCharacteristics(Spliterator.SIZED|Spliterator.SUBSIZED)) {
        for(;;) {
            Spliterator<T> part=sp.trySplit();
            if(part==null) break;
            if(sp.getExactSizeIfKnown()==0) {
                sp=part;
                break;
            }
        }
    }
    T value=null;
    for(Iterator<T> it=recursive(sp); it.hasNext(); )
        value=it.next();
    return value;
}

private static <T> Iterator<T> recursive(Spliterator<T> sp) {
    Spliterator<T> prev=sp.trySplit();
    if(prev==null) return Spliterators.iterator(sp);
    Iterator<T> it=recursive(sp);
    if(it!=null && it.hasNext()) return it;
    return recursive(prev);
}

您可以使用以下示例来说明差异:

String s=getLast(
    IntStream.range(0, 10_000_000).mapToObj(i-> {
        System.out.println("potential heavy operation on "+i);
        return String.valueOf(i);
    }).parallel()
);
System.out.println(s);

它将打印:

potential heavy operation on 9999999
9999999

换句话说,它没有对前9999999个元素执行操作,而只对最后一个元素执行操作。


推荐