英文:
Force Stream::filter method to fail compile time when Predicate<? super Object> is passed rather than Predicate<? super T>
问题
我正在尝试使用预定义的身份过滤器来与流 API 一起使用。不幸的是,我无法正确返回与流 API 文档符合的通用谓词。
根据反编译器,这是Stream::filter
的定义:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> var1);
}
我在任何支持流的 Java 版本(8~15)中都遇到了问题。问题与我的实现无关。以下代码实际上足以重现此问题:
Collection<String> result = Stream.of("A", "B", "C")
.filter(new Object()::equals)
.filter(Integer.valueOf(-1)::equals)
.collect(Collectors.toSet());
在这里,应用了两个谓词,它们都不符合<? super String>
...
根据这个答案,这种行为似乎很奇怪...
我应该如何防止我的库用户通过随机对象平等检查等方式对ServerState
进行过滤?
理想情况下,我希望始终返回正确的Predicate<? super T>
,不幸的是,这没有任何编译时错误支持...
在这种情况下,使用代码检查工具并不是解决方案。
尽管我知道如何使用下界通配符,但我之前忽略了Predicate<? super Integer>
实际上可以成功转换为Predicate<? super String>
。
其中:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
导致[]
空结果集。
这是我目前的情况,但对其中任何部分都不满意:
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Collection<Integer> result = Stream.of(1, 2, 3)
//.filter(Filters.is_tClass(Integer.class, 4)) // 强制用户提供目标类
//.filter(Filters.is_comparable(5)) // 仅使用 Comparable
.filter(Filters.is(new Server())) // 在运行时使用自定义异常失败
.collect(Collectors.toSet());
System.out.println(result);
}
private static class Server {
}
private static class Filters {
private static <T> Predicate<? super T> is(T other) {
return t -> {
// 简单的类相等性检查 - 容易出错!
Class<?> tClass = t.getClass();
Class<?> otherClass = other.getClass();
if (!tClass.equals(otherClass)) {
throw new RuntimeException(
String.format("Check equality for [%s ? %s] seems odd. Can not continue...", tClass, otherClass));
}
return t.equals(other);
};
}
static <T> Predicate<? super T> is_tClass(Class<T> tClass, T other) {
return is(other);
}
static <T extends Comparable<T>> Predicate<? super T> is_comparable(T other) {
return is(other);
}
}
}
在发布示例之前不存在is_*
类型的方法名称,因此将被删除...
编辑
尽管我知道如何使用下界通配符,但我之前忽略了Predicate<? super Integer>
实际上可以成功转换为Predicate<? super String>
。
其中:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
导致[]
空结果集。
英文:
I'm playing around with predefined Identity filters for use with the stream api. Unfortunately I'm unable to properly return a generic predicate that is compliant with the stream api documentation.
According to the de-compiler here is the Stream::filter
definition:
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> var1);
I'm facing the issue with any Java version that has Streams support (8~15). The issue has nothing to do with my implementation. This code actually is enough in order to reproduce it:
Collection<String> result = Stream.of("A", "B", "C")
.filter(new Object()::equals)
.filter(Integer.valueOf(-1)::equals)
.collect(Collectors.toSet());
Here, two predicates are applied where both of them aren't <? super String>
compliant...
According to this answer this behavior seems to be strange...
How should I prevent users of my library from filtering on ServerState
by random Object equality check, etc...?
Ideally I would like to always return proper Predicate<? super T> unfortunately that is not backed up by any compile time error...
Using a linter is not a solution in that case.
Even though I know how lower bounded wildcards work what I've been missing is that a Predicate<? super Integer>
could be successfully casted to Predicate<? super String>
.
Where:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
results in []
empty resultset.
Here is what I have so far, but not happy with any of it:
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Collection<Integer> result = Stream.of(1, 2, 3)
//.filter(Filters.is_tClass(Integer.class, 4)) // enforce user to provide target class
//.filter(Filters.is_comparable(5)) // use only Comparable
.filter(Filters.is(new Server())) // fail runtime with custom exception
.collect(Collectors.toSet());
System.out.println(result);
}
private static class Server {
}
private static class Filters {
private static <T> Predicate<? super T> is(T other) {
return t -> {
// simple class equality check - error prone!
Class<?> tClass = t.getClass();
Class<?> otherClass = other.getClass();
if (!tClass.equals(otherClass)) {
throw new RuntimeException(
String.format("Check equality for [%s ? %s] seems odd. Can not continue...", tClass, otherClass));
}
return t.equals(other);
};
}
static <T> Predicate<? super T> is_tClass(Class<T> tClass, T other) {
return is(other);
}
static <T extends Comparable<T>> Predicate<? super T> is_comparable(T other) {
return is(other);
}
}
}
Methods with names of the type is_*
did not exist before posting the sample in here and therefor will be removed...
EDIT
Even though I know how lower bounded wildcards work what I've been missing is that a Predicate<? super Integer>
could be successfully casted to Predicate<? super String>
.
Where:
Predicate<? super String> stringPredicate = (Predicate<? super String>)Filters.is_tClass(Integer.class, 4);
Predicate<? super Server> serverPredicate = (Predicate<? super Server>)Filters.is_comparable(5);
Collection<Integer> result = Stream.of(1, 2, 3)
.filter((Predicate<? super Integer>)stringPredicate)
.filter((Predicate<? super Integer>)serverPredicate)
.filter(Filters.is(new Object()))
.collect(Collectors.toSet());
results in []
empty resultset.
答案1
得分: 5
以下是翻译好的内容:
> 在这里,应用了两个断言,其中两者都不符合 <? super String>
这是不正确的:这两个断言确实消耗了一个 Object
,而 Object
是 String
的父类。
<? super String>
不能与 <? extends String>
混淆。
英文:
> Here, two predicates are applied where both of them aren't <? super String> compliant
It's not true: the 2 predicates do consume an Object
, which is the parent of String
.
<? super String>
must not be confused with <? extends String>
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论