获取列表的最小和最大字符串

时间:2015-12-28 20:41:07

标签: java string java-8 java-stream

我有一个List<String> list,并希望按字母顺序获取该列表的第一个和最后一个字符串。我想使用Java 8和Streams与收集器的强大功能来解决这个问题。

这不起作用:

String first = list.stream().collect(Collectors.minBy(String.CASE_INSENSITIVE_ORDER));

它给了我一个编译器错误:

  

类型不匹配:无法从Optional转换为String

你能解释一下为什么并告诉我做我想做的最好方法吗?

3 个答案:

答案 0 :(得分:7)

Collectors.minByCollectors.maxBy返回Optional:如果Stream为空,则返回空Optional;否则,将返回包含结果的Optional

如果您希望在Stream为空时拥有默认值(或仅null),则可以拨打orElse

String first = list.stream().collect(minBy(String.CASE_INSENSITIVE_ORDER)).orElse(null);

此外,如果您确定Stream不为空,则可以直接致电get()并检索该值。

作为旁注,您还可以通过调用Collections.min(分别为Collections.max)来返回最小值:

String first = Collections.min(list, String.CASE_INSENSITIVE_ORDER);

无需创建Stream管道。请注意,如果列表为空,这将引发异常。

答案 1 :(得分:5)

错误信息非常清楚。 the javadoc也是如此:Collector.minBy()会生成Optional<T>类型的结果,即Optional<String>

为什么呢?因为如果流恰好是空的,它不能返回任何字符串。因此,您需要get collect()返回的Optional中的字符串值。{/ p>

请注意,get()将抛出异常,因为流为空,因此找不到最小值coult。如果那是你想要的,因为永远不会发生空列表,那就没问题了。否则,您应该使用orElse()或orElseThrow()来返回备用默认值,或者抛出另一个异常。

答案 2 :(得分:0)

你提到你想要列表中的最小值和最大值。没有标准的收集器可以做到这一点,但你可以自己创建:

class ExtremesCollector<T> {
    private final Comparator<T> comparator;
    private Optional<T> min = Optional.empty();
    private Optional<T> max = Optional.empty();

    public static Collector<T> collector(Comparator<T> comparator) {
        return Collector.of(() -> new ExtremesCollector(comparator),
            ExtremesCollector::accept, ExtremesCollector::combine);
    }

    public Optional<T> getMin() {
        return min;
    }

    public Optional<T> getMax() {
        return max;
    }

    private ExtremesCollector(Comparator<T> comparator) {
        this.comparator = comparator;
    }

    private void accept(T value) {
        if (!min.isPresent() || comparator.compare(min.get(), value) < 0)
            min = Optional.of(value):
        if (!max.isPresent() || comparator.compare(max.get(), value) > 0)
            max = Optional.of(value):
    }

    private ExtremesCollector combine(ExtremesCollector other) {
        if (other.min.isPresent())
            accept(other.min.get());
        if (other.max.isPresent())
            accept(other.max.get());
    }
}

这可以按照您的预期使用:

ExtremesCollector extremes = myList.parallelStream()
    .collect(ExtremesCollector.collector(String.CASE_INSENSITIVE_ORDER));
extremes.getMax().ifPresent(System.out::println);
extremes.getMin().ifPresent(System.out::println);

相比,使用内置minmax方法的唯一优势是效率。