Pat*_*eer 6 java generics lambda java-8
我有两个通用方法,旨在强制调用者提供类型匹配的参数:
private <T> void compareValues(Supplier<T> supplier, T value) {
System.out.println(supplier.get() == value);
}
private <T> void setValue(Consumer<T> consumer, T value) {
consumer.accept(value);
}
Run Code Online (Sandbox Code Playgroud)
但是,在调用它们时,编译器对允许作为参数传递的内容有不同的理由:
compareValues(this::getString, "Foo"); // Valid, as expected
compareValues(this::getInt, "Foo"); // Valid, but compiler should raise error
compareValues(this::getString, 1); // Valid, but compiler should raise error
setValue(this::setString, "Foo"); // Valid, as expected
setValue(this::setInt, "Foo"); // Type mismatch, as expected
setValue(this::setString, 1); // Type mismatch, as expected
private String getString() {
return "Foo";
}
private int getInt() {
return 1;
}
private void setString(String string) {
}
private void setInt(int integer) {
}
Run Code Online (Sandbox Code Playgroud)
怎么会?编译器是否过于笨拙以至于无法在此处正确推理类型,或者这是类型系统的一个特性?如果是这样,导致这种行为的规则是什么?另外,如果可能的话,如何在不添加人工参数的情况下创建compareValues的"类型安全"版本?
请注意,提供的方法只包含一个虚拟实现,并不反映我实际代码库中的代码.这里的重点仅仅是方法调用.
其他人已经提到了为什么会发生这种情况,因此这里有一个解决该问题的解决方案。
如果您创建一个泛型类,将供应商的传递与参数的传递分开,则编译器没有机会选择交集类型:
public class Comparer<T>
{
private final Supplier<T> supplier;
Comparer(final Supplier<T> supplier)
{
this.supplier = supplier;
}
void compare(T value)
{
System.out.println(supplier.get() == value);
}
}
new Comparer<>(this::getString).compare("Foo"); // Valid, as expected
new Comparer<>(this::getInt).compare("Foo"); // Invalid, compiler error
new Comparer<>(this::getString).compare(1); // Invalid, compiler error
Run Code Online (Sandbox Code Playgroud)
通过分离此行为,您还可以Comparer执行潜在有用的操作,例如缓存Supplier.get().
| 归档时间: |
|
| 查看次数: |
151 次 |
| 最近记录: |