Java 具有已知边界的流最小值

Java Stream minimum with known bound

我有一个列表流,我想从中获取元素最少的条目。我当然可以做类似

的事情
Stream<List<T>> s = ...
s.min((e1, e2) -> e1.size() - e2.size());

但在这种情况下,我们知道最小值的下限,因为大小是非负的。这意味着当找到大小为 0 的列表时,我们实际上可以停止,而不是 运行 遍历列表的其余部分。 这可以通过 Java Streams 以一种体面的方式实现吗?

我会想象它看起来像这样,提供一个比较器和一个函数,告诉我们当前最小值何时是全局最小值:

s.boundedMin(
    (e1, e2) -> e1.size() - e2.size(),
    e -> e.size() == 0
)

我想不出实现它的方法。

当然我可以只使用 Iterable 并使用带有 break 语句的循环来获得它,我只是想知道流是否也可以让我到达那里。

编辑: 为了让它更清楚一点。流 可能 可能不 包含大小为 0 的列表。我的问题是 min() 将 运行 通过整个流,即使它已经找到了一个大小为 0 的列表(这已经是它所能得到的最小的列表)。所以,我正在寻找的是 min 的实现,它不需要扫描整个流,通过提供最小值的下限。

编辑2: 没有流的等效迭代解决方案是

List<List<T>> s = ...
List<T> min = null;
for (List<T> l : s) {
        if (min == null || min.size() > l.size())
            min = l;
        if (min.size() == 0) {
            break;
        }
}

只是为了好玩:

static <T> int size(Stream<List<T>> st) {

    class MinHolder implements Consumer<List<T>> {

        private int min = Integer.MAX_VALUE;

        public void accept(List<T> l) {
            if (min > l.size()) {
                min = l.size();
            }
        }
    }

    MinHolder holder = new MinHolder();
    Spliterator<List<T>> sp = st.spliterator();

    int elements = 0;
    for (; sp.tryAdvance(holder) && holder.min > 0; ++elements) {

    }

    System.out.printf("took %s elements to find the min%n", elements);
    return holder.min;
}

还有一些测试用例:

public static void main(String[] args) {
    Stream<List<Integer>> st = Stream.of(List.of());
    System.out.println(size(st));

    st = Stream.empty();
    System.out.println(size(st));

    st = Stream.of(List.of(), List.of(1), List.of(1, 2), List.of(1, 2, 3));
    System.out.println(size(st));
}

如果你不是被迫使用 Stream<List<T>> 那么就不要;这种 有条件的 中断不是 Streams 的设计目的,许多人会认为这是一种滥用。