我有一个List<String> list
,并希望按字母顺序获取该列表的第一个和最后一个字符串。我想使用Java 8和Streams与收集器的强大功能来解决这个问题。
这不起作用:
String first = list.stream().collect(Collectors.minBy(String.CASE_INSENSITIVE_ORDER));
它给了我一个编译器错误:
类型不匹配:无法从Optional转换为String
你能解释一下为什么并告诉我做我想做的最好方法吗?
答案 0 :(得分:7)
Collectors.minBy
和Collectors.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);
相比,使用内置min
和max
方法的唯一优势是效率。