为何List<Integer>的forEach可接受非Integer父类型的Consumer?
问题解析:为什么List的forEach可以传入操作String的Lambda
先拆解清楚核心逻辑,你误解的点在于把Lambda内部的操作类型和Consumer的参数类型混为一谈了:
forEach的泛型约束本质
对于List<Integer>,它的forEach方法签名是void forEach(Consumer<? super Integer> action)——这里要求的是:这个Consumer能接受Integer或者它的任意父类型的参数。注意,是Consumer的输入参数类型要满足? super Integer,和Consumer内部做什么操作完全无关。你的Lambda实际对应的类型
看这段代码:
ints.forEach(x -> { if (x != null) nonNullStrings.add(x.toString()); });
这里的x是Integer类型(因为ints是List<Integer>,forEach遍历的元素都是Integer),所以这个Lambda对应的是Consumer<Integer>。而Integer本身就属于? super Integer的范畴(Java里一个类型自己也是自己的超类型),完全符合forEach的泛型要求。
- 纠正你的误解
你误以为Lambda内部操作了String就需要Consumer<String>,但实际上Lambda的参数类型由forEach的上下文(也就是List的元素类型)决定,和Lambda内部生成的String无关。这个Lambda只是把每个Integer转成String再添加到另一个List,它本身还是接受Integer作为输入的Consumer,完全满足约束条件。
对比下面strings.forEach的代码,它的Lambda是Consumer<String>,符合List<String>的forEach要求的Consumer<? super String>,逻辑是完全一致的。
内容的提问来源于stack exchange,提问作者Sayyed Dawood
相关产品推荐
相关产品推荐

