为什么这些Java 8个Lambda表达式中的类型转换行为不同?

问题描述 投票:9回答:3
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接口。同时的forEach走的是消费者接口与同一原始参考类型<? super T>和编译器是抱怨为整数参数值。

java java-8 java-stream
3个回答
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,但既然你已经使用流作为原料 - 一切是生了。


2
投票

正如上面你被告知要使用原始流。如果要在整数迭代,那么你需要为流指定通用。

例如

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它将编译,即使你将提供一组字符串。例如

    Stream st = Stream.of("1","2","3","4");
    st.collect(Collectors.averagingInt((Integer x)->x));

但是它会与ClassCastException异常运行时失败。这里的区别是,averagingInt tryes投下所有传入的类型来具体和foreach只是使用类型,是什么可能会导致编译失败。

它相当于

    ToIntFunction<? super Integer> mapper = new ToIntFunction<Integer>(){
        @Override
        public int applyAsInt(Integer value) {
            return value;
        }
    };

    st.collect(Collectors.averagingInt(mapper));

匿名类将averagingInt的内部和通过参数传递给applyAsInt方法将被转换为适当的类型(我的样品中的整数)之前使用

另一个有趣的事情

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 

1
投票

该签名是不同的。

Collectors.averagingInt接受ToIntFunction,其操作collect的返回类型被绑定到Stream的类型,这是生的。

Stream.forEach接受Consumer,其直接绑定到Stream的类型。

原始类型与您在forEach指定类型干扰的能力,因为类型安全的,所以你导致编译错误。

© www.soinside.com 2019 - 2024. All rights reserved.