如何自定义 PriorityQueue.stream().foreach 以按优先级顺序迭代

J.J*_*eam 2 java priority-queue java-stream

我有一个里面有 PriorityQueue 字段的类:

public class MyClass<T>{
    Queue<T> queue = new PriorityQueue<>();
Run Code Online (Sandbox Code Playgroud)

我想以某种方式从 MyClass 获取一个流并使用 foreach 并希望序列按照我的 PriorityQueue 的优先级顺序运行。最简单的方法是覆盖 stream() 方法:

@Override
public Stream stream() {
    return queue.stream();
}
Run Code Online (Sandbox Code Playgroud)

但这不会按优先级顺序公开队列元素。所以问题是:如何让 foreach 流方法表现得像:

    while(!queue.isEmpty()) 
        queue.poll();
Run Code Online (Sandbox Code Playgroud)

mic*_*alk 5

您可以使用Stream::generateandQueue::poll方法来创建一个Streamwith 元素PriorityQueue 并保持它们的顺序:

@Override
public Stream<T> stream() {
    return Stream.generate(queue::poll);
}
Run Code Online (Sandbox Code Playgroud)

然而,这可能是危险的,因为它Stream::generatepoll不断地调用,所以它可能是一个无限的流。因此Stream::limit应考虑与队列大小一起使用:

@Override
public Stream<T> stream() {
    return Stream.generate(queue::poll)
        .limit(queue.size());
}
Run Code Online (Sandbox Code Playgroud)

或者你可以简单地返回排序流:

@Override
public Stream<T> stream() {
    return queue.stream()
            .sorted(comparator);
}
Run Code Online (Sandbox Code Playgroud)

其中比较器是您的比较器。

Java 9 中,您可以使用Stream::takeWhilewith 拒绝空值的谓词。正如Queue::poll将返回null时队列为空-所得Stream将包含在它们的顺序从队列中的元素(这是另一种使用limit如在第一溶液中所述):

@Override
public Stream<T> stream() {
    return Stream.generate(queue::poll)
            .takeWhile(Objects::nonNull);
}
Run Code Online (Sandbox Code Playgroud)

  • *谨防*。`Stream.generate` 创建一个*无序*流,这完全违背了按优先级顺序迭代的目的。它碰巧以顺序流所需的顺序处理元素,但这并不是保证的行为。创建“已排序”流是一种安全的解决方案,它也不会清空队列,这是在集合上进行流式传输时通常的预期行为。 (2认同)