Zz'*_*Rot 5 java java-8 method-reference
在Java Precisely 3rd Ed.中,有以下代码片段:
BiConsumer<Double[], Comparator<Double>> arraySorter = Arrays::<Double>sort;
但是,我注意到即使我不在<Double>之后::,方法引用仍然有效(由于类型参数,这是有意义的BiConsumer).
不过,我很困惑,是否有何种情况下::<T>会需要在方法的参考,如果是这样,一个例子将是非常有益.
这是实际中的类型推断,在大多数情况下,编译器会为您推断类型,因此意味着您无需明确提供它们。
但是,在某些情况下,您需要手动提供类型提示。
无论如何,Java 8 增强了泛型参数的推断。
因此,请执行以下操作:
BiConsumer<Double[], Comparator<Double>> arraySorter = Arrays::sort;
由于类型推断,完全有效。
我现在能想到的几个在 Java-7 中不起作用但在 Java-8 中起作用的例子是这样的:
void exampleMethod(List<Person> people) {
      // do logic
} 
exampleMethod(Collections.emptyList())
另一个例子:
someMethodName(new HashMap<>());
...
void someMethodName(Map<String, String> values);
您之前需要明确提供类型参数。
此外,由于上述类型推断,这就是我们现在可以执行以下操作的确切原因:
...
...
.collect(Collectors.toList());
而不是这个人:
...
...
.collect(Collectors.<Person>toList());
在某些情况下是否应该显式提供类型参数是一个偏好问题,在其他情况下,您必须这样做以帮助编译器完成其工作。
我认为Java 10的局部变量类型推断(var name = ...;)将解决这个难题。代替目标变量类型提供方法引用的类型,右侧将需要完全指定类型,这需要::<T>在方法引用上使用类型参数()。
首先想到了大门...
var arraySorter = Arrays::<Double>sort;
...但是方法引用本身并没有定义类型。它们需要由编译器转换为功能对象,并且即使存在确切的类型,编译器也不会搜索寻找适当类型的已知功能接口。
接下来的想法是使用方法引用作为方法的参数,该方法基于该方法的参数返回类型。
class Spy {
    static <T> Function<T,T> f2(Function<T,T> f) {
        return f.andThen(f);
    }
    static <T> T identity(T t) {
        return t;
    }
}
使用此方法,我们可以创建传递给方法的方法引用的局部变量:
Function<Double,Double> double_identity = f2(Spy::<Double>identity);
如预期的那样,我们可以删除 ::<Double>
Function<Double,Double> double_identity = f2(Spy::identity);
出乎意料的是,使用局部变量类型推断就可以了。
var double_identity = f2(Spy::identity);             // Infers <Object>!
Object obj = null;
double_identity.apply(obj); 
但是,当使用方法引用类型覆盖它时,真正的惊喜就来了。
var double_identity = f2(Spy::<Double>identity);     // Error: Double != Object
经过一番战斗,我弄清楚了原因。我们必须将类型应用于f2方法本身:
var double_identity = Spy.<Double>f2(Spy::identity); // Works.
回想起来,这是有道理的。变量的类型通常为外部函数提供上下文。通过将结果分配给Function<Double,Double>变量,编译器可以推断的类型f2(...),然后将该类型传递给参数。在var name = ...没有显式类型的情况下,唯一可用的类型是Object,因此编译器进行推断Spy.<Object>f2(...),然后确定参数类型必须为Function<Object,Object>。
不幸的是,它似乎没有从内到外进行解析,因此Spy::<Double>identity不会导致函数被推断为Spy.<Double>f2(...),而变量被推断为Function<Double,Double>。也许Java 11?可能会损坏太多,无法正常工作。
但是,它的确终止了我var name = ...;为解决OP难题而进行的滥用尝试。
非常感谢@Eugene批评了我在Java 10发行之前的尝试。
| 归档时间: | 
 | 
| 查看次数: | 593 次 | 
| 最近记录: |