Stream st = Stream.of(1,2,3,4);
这会创建整数流(通过在运行时进行推断)还是对象流?
st.collect(Collectors.averagingInt((Integer x)->x));
此行编译正常。
st.forEach((Integer x)-> System.out.println(x));
此行不编译。它提供了在(整数x)编译错误,说预期目标,但发现整数。为什么?
为何不为上述averagingInt方法抱怨相同?
averagingInt采用原始参考类型为<? super T>
的ToIntFunction接口,并允许使用Integer值。在forEach使用与<? super T>
相同的原始引用类型的Consumer接口时,编译器在抱怨Integer参数值。
答案 0 :(得分:4)
这是创建整数流(通过在运行时进行推断)还是对象流?
泛型在运行时不存在,没有什么可在运行时“推断”的。由于您为Stream st
使用了原始类型-如果需要,它是Stream<Object>
。
好吧,即使是您写的东西(也确实可以编译):
st.collect(Collectors.averagingInt((Integer x)->x));
当您尝试添加预期结果时将无法编译:
Double i = st.collect(Collectors.averagingInt((Integer x) -> x));
我想知道您是否像下面这样重写将更有意义:
Collector<Integer, ?, Double> collector = Collectors.averagingInt((Integer x) -> x);
Double result = st.collect(collector); // does not compile
推论对Collectors.averagingInt
有用,但是由于您将Stream用作原始数据-其他所有内容也都是原始数据。
答案 1 :(得分:2)
如上所述,您正在尝试使用原始Stream。如果要遍历Integer,则需要为Stream指定泛型。
例如
Stream<Integer> st = Stream.of(1,2,3,4);
然后它将进行编译。
这个问题等同于在旧样式的通用集合中进行迭代的问题
Collection values = Arrays.asList(1,2,3,4);
for(Integer v: values){
System.out.println(v);
}
上面的代码无法编译,因为值是对象列表而不是整数。
对于 averagingInt ,即使您提供 String列表,它也会编译。例如
Stream st = Stream.of("1","2","3","4");
st.collect(Collectors.averagingInt((Integer x)->x));
但是,它将在运行时由于ClassCastException而失败。此处的区别在于averagingInt尝试将所有传入类型转换为特定类型,而forEach仅使用类型,因为这可能导致编译失败。
等价
ToIntFunction<? super Integer> mapper = new ToIntFunction<Integer>(){
@Override
public int applyAsInt(Integer value) {
return value;
}
};
st.collect(Collectors.averagingInt(mapper));
匿名类将在averagingInt内部使用,在将args传递给applyAsInt方法之前,它将被强制转换为适当的类型(在我的示例中为Integer)
另一个有趣的事情
Stream st = Stream.of(1,2,3,4);
Consumer<String> stringConsumer = new Consumer<String>() {
@Override
public void accept(String o) {
}
};
st.forEach(stringConsumer); // will compile disregarding to raw type of Stream and specific Consumer
st.forEach((Integer a) -> System.out.println(a)); // will fail because os raw Stream
答案 2 :(得分:1)
签名是不同的。
Collectors.averagingInt
接受ToIntFunction
,其中操作collect
的 return 类型绑定到Stream
类型,即原始的。
Stream.forEach
接受Consumer
,该{<1>直接绑定到Stream
的类型。
原始类型会干扰您在forEach
中指定类型的能力,因此由于类型安全性,您将导致编译错误。