guava/src/com/google/common/collect/Comparators.java
public static <T> Collector<T, ?, List<T>> least(int k, Comparator<? super T> comparator) {
    checkNonnegative(k, "k");
    checkNotNull(comparator);
    return Collector.of(
        () -> TopKSelector.<T>least(k, comparator),
        TopKSelector::offer,
        TopKSelector::combine,
        TopKSelector::topK,
        Collector.Characteristics.UNORDERED);
  }
public static <T> Collector<T, ?, List<T>> least(int k, Comparator<? super T> comparator) {
    checkNonnegative(k, "k");
    checkNotNull(comparator);
    return Collector.of(
        () -> TopKSelector.<T>least(k, comparator),
        TopKSelector::offer,
        TopKSelector::combine,
        TopKSelector::topK,
        Collector.Characteristics.UNORDERED);
  }
Returns a {@code Collector} that returns the {@code k} smallest (relative to the specified
{@code Comparator}) input elements, in ascending order, as an unmodifiable {@code List}. Ties
are broken arbitrarily.

<p>For example:

<pre>{@code
Stream.of("foo", "quux", "banana", "elephant")
.collect(least(2, comparingInt(String::length)))
// returns {"foo", "quux"}
}</pre>

<p>This {@code Collector} uses O(k) memory and takes expected time O(n) (worst-case O(n log
k)), as opposed to e.g. {@code Stream.sorted(comparator).limit(k)}, which currently takes O(n
log n) time and O(n) space.

@throws IllegalArgumentException if {@code k < 0}
@since 22.0