今天遇到一个问题: 发现 Optional#filter 和 Stream#filter返回的结果不一致?
做个简单小实验
给定一个List 类型的数据集 strList1, 通过filter过滤集合中不包含在 strList2的结果集 resList;
数据集
List<String> strList1 = Arrays.asList("lizhaoyang", "zhaoyang", "softsun", "lzy");
List<String> strList2 = Arrays.asList("lizhaoyang", "lzy");
// 期望结果
List<String> expectList = Arrays.asList("zhaoyang", "softsun");
实验1: 通过 Optional#filter 来实现
List<String> realList1 = Optional.ofNullable(strList1).
filter(l -> !strList2.contains(l)).orElse(Collections.emptyList());
实验2: 通过Stream#filter来实现
List<String> realList2 = strList1.stream().filter(l -> !strList2.contains(l))
.collect(Collectors.toList());
实验结论
:::info
java.util.Optional#filter res: false
java.util.stream.Stream#filter res: true
:::
完整代码
public class FilterDemo {
public void test1() {
List<String> strList1 = Arrays.asList("lizhaoyang", "zhaoyang", "softsun", "lzy");
List<String> strList2 = Arrays.asList("lizhaoyang", "lzy");
// 期望结果
List<String> expectList = Arrays.asList("zhaoyang", "softsun");
List<String> realList1 = Optional.ofNullable(strList1).
filter(l -> !strList2.contains(l)).orElse(Collections.emptyList());
// org.apache.commons.collections4.CollectionUtils#isEqualCollection(java.util.Collection<?>, java.util.Collection<?>)
boolean assertRes = CollectionUtils.isEqualCollection(realList1, expectList);
System.out.println("java.util.Optional#filter res: " + assertRes);
}
public void test2() {
List<String> strList1 = Arrays.asList("lizhaoyang", "zhaoyang", "softsun", "lzy");
List<String> strList2 = Arrays.asList("lizhaoyang", "lzy");
// 期望结果
List<String> expectList = Arrays.asList("zhaoyang", "softsun");
List<String> realList2 = strList1.stream().filter(l -> !strList2.contains(l))
.collect(Collectors.toList());
// org.apache.commons.collections4.CollectionUtils#isEqualCollection(java.util.Collection<?>, java.util.Collection<?>)
boolean assertRes = CollectionUtils.isEqualCollection(realList2, expectList);
System.out.println("java.util.stream.Stream#filter res: " + assertRes);
}
public static void main(String[] args) {
FilterDemo f = new FilterDemo();
f.test1();
f.test2();
}
}
原因分析:
猜测原因: Optional#filter 和 Stream#filter 入参 类型不一致 或者 filter实现不一致;具体看源码, 发现其实没有差别; 那么具体是哪里的问题呢?
// java.util.Optional#filter
/**
* If a value is present, and the value matches the given predicate,
* return an {@code Optional} describing the value, otherwise return an
* empty {@code Optional}.
*
* @param predicate a predicate to apply to the value, if present
* @return an {@code Optional} describing the value of this {@code Optional}
* if a value is present and the value matches the given predicate,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the predicate is null
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
//java.util.Arrays.ArrayList#indexOf
// o 是 strList1 ; a 是 strList2 数组;o.equals(a[i])是永远不可能相等的
@Override
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
// java.util.stream.Stream#filter
/**
* Returns a stream consisting of the elements of this stream that match
* the given predicate.
*
* <p>This is an <a href="package-summary.html#StreamOps">intermediate
* operation</a>.
*
* @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
* <a href="package-summary.html#Statelessness">stateless</a>
* predicate to apply to each element to determine if it
* should be included
* @return the new stream
*/
Stream<T> filter(Predicate<? super T> predicate);
//java.util.stream.Stream#filter 的实现
//java.util.stream.ReferencePipeline#filter
@Override
public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
Objects.requireNonNull(predicate);
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
StreamOpFlag.NOT_SIZED) {
@Override
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override
public void begin(long size) {
downstream.begin(-1);
}
@Override
public void accept(P_OUT u) {
if (predicate.test(u))
downstream.accept(u);
}
};
}
};
}
关于java.util.Optional#filter和java.util.stream.Stream#filter的入参其实都是 java.util.function.Predicate类型一致。但是注意 java.util.function.Predicate<T> T 是关键; Optional#filter 的T和Stream#filter 的 T不一致。 因此 可以得出一下结论。
结论
两者 filter的入参类型不一致;Optional#filter 的入参 l表示的是 List; 而 Stream#filter 的入参 l的类型是 String类型; 因此结论就不一致;
Optional#filter(l -> !strList2.contains(l)) -> List 类型
Stream#filter(l -> !strList2.contains(l)) -> String类型
本文探讨了在使用Optional#filter和Stream#filter时遇到的结果不一致问题。通过实验展示了在不同场景下,两个方法的过滤操作如何导致不同的输出。实验表明,关键在于Optional#filter和Stream#filter的参数类型不同,导致了最终结论的差异。
1万+

被折叠的 条评论
为什么被折叠?



