假设有一个User实体类,有方法getId()、getName()、getAge()等方法,现在想要将User类型的流收集到一个Map中,示例如下:
Stream<User> userStream = Stream.of(new User(0, "张三", 18), new User(1, "张四", 19), new User(2, "张五", 19), new User(3, "老张", 50));
Map<Integer, User> userMap = userSteam.collect(Collectors.toMap(User::getId, item -> item));
将stream转成map有如下api:
由toMap接收的参数可以知道,toMap接收的第一个参数是Function类型的,但是User::getId
方法就是如下:
public Integer getId() {
return id;
}
可以看到这个方法不接收任何参数,返回一个值。但是Function接口的定义是接口的抽象方法接收一个参数并且做一些处理然后返回。那为啥User::getId
传入toMap方法而不报错呢?说好的引用方法时实例方法的参数列表和返回值类型要与函数式接口中抽象方法的参数列表和返回值类型要一致呢?
直到我看到一篇文章的这一段:
若果我们学过sql语句的话会了解到,groupby这个方法我们会常常用到。现在我们通过看源码了解这个方法是怎么实现的。这个方法的最终样貌是下面
public static <T, K, D, A, M extends Map<K, D>>
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
当你使用的是
groupingBy(e->e.getName())
其实调用了
groupingBy(e->e.getName(),toList())
而最后调用了
groupingBy(e->e.getName(),HashMap::new,toList())
以上面为例子,我们知道最后结果承载的容器是Map,更加准确的说,是一个HashMap。所以
supplier = HashMap::new
由上面这一段忽然之间明白了其实上面的User::getId
其实就是
Function<User,Integer> fun = (user)->user.getId()
可以和下面的代码对比
Supplier<Integer> sup = ()->user.getId();
同理可得
Function<User,Integer> after = (user)->user.getName().length();