Stream Collectors - toMap

news/2025/2/25 19:05:31

public static <T,​K,​U> Collector<T,​?,​Map<K,​U>> toMap​(Function<? super T,​? extends K> keyMapper, Function<? super T,​? extends U> valueMapper)

简单理解就是把元素放到map中保存,map中的key和value都是根据元素计算而来。

先看两个官方的例子:

Map<Student, Double> studentToGPA

   = students.stream().collect(

     toMap(Function.identity(),

           student -> computeGPA(student)));

这个例子作用很明显,就是把student集合中的每个student放到map中保存,key取student这个对象本身,value通过computeGPA这个方法对student进行计算得出。

再看一个例子:

Map<String, Student> studentIdToStudent

   = students.stream().collect(

     toMap(Student::getId,

           Function.identity()));

作用和上面一样,key取值student对象中的id,value取student这个对象本身。

再看两个例子:

void test31() {

        List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail3","adr3")));

        Map<User, String> map = userList.stream().collect(Collectors.toMap(a -> a, b -> b.getAddr()));

        map.forEach((k,v) -> System.out.println(k.toString()+ ":"+ v));

    }

运行结果:

com.azhu.java8.optionalStudy.User@769c9116:a2

com.azhu.java8.optionalStudy.User@6aceb1a5:adr3

com.azhu.java8.optionalStudy.User@6956de9:adr1

 

假设有个需求,需要把User类型的集合中的所有User取其mail为key,addr为value保存在map中返回。

void test31() {

        List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail3","adr3")));

        Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr()));

        map.forEach((k,v) -> System.out.println(k+ ":"+ v));

    }

运行结果:

mail3:adr3

mail2:a2

mail1:adr1

 

public static <T,​K,​U> Collector<T,​?,​Map<K,​U>> toMap​(Function<? super T,​? extends K> keyMapper, Function<? super T,​? extends U> valueMapper, BinaryOperator<U> mergeFunction)

相比上一个函数多了一个参数,mergeFunction根据其含义就能理解这就是一个数据合并的方法。其作用就是当集合元素中根据key计算方法得出了相同的Key值就根据mergeFunction方法对这两个key值相同的元素进行处理得到一个value。

在上面那个方法中如果存在同样的key就会抛出异常。看个例子:

void test32() {

        List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail1","adr3")));

        Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> c+" - "+d));

        map.forEach((k,v) -> System.out.println(k+ ":"+ v));

    }

以上例子中存在两个mail1,因此如果用第一个toMap方法处理就会报异常,在这里我们添加了一个出现重复key这种情况的处理方法,我们把所有重复key的value通过“-”符号连接起来形成一个key value键值对。上面代码执行结果如下:

mail2:a2

mail1:adr1 - adr3

 

这里再说一下mergeFunction函数处理流程,入参是两个,代码中定义的是c,d;执行流程是第一次遇到重复key的时候把第一个把key对应的value赋值给c,把第二个key对应的value赋值给d,然后这两个重复key保留一个,把这两个value用“-”连接起来当作其对应的value然后继续执行,当再次遇到相同key的时候再重复上面的步骤。上面例子如果还有一个user(“mail1”,”adr4”),那运行结果就是:mail1:adr1 - adr3 – adr4

 

public static <T,​K,​U,​M extends Map<K,​U>> Collector<T,​?,​M> toMap​(Function<? super T,​? extends K> keyMapper, Function<? super T,​? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)

这个方法又多了一个参数,根据参数字面意思也能理解这个参数是用来定义最终返回的数据类型的,上面的方法默认返回的是HashMap类型,如果我们不想要这个类型就可以添加这个参数来自定义返回的数据类型。

参数定义:Supplier<M> mapFactory  这个函数参数传递数据类型是M,再看看返回数据类型的定义:M extends Map<K,​U> 因此自定义的数据类型只能是实现Map接口的数据类型。

看个例子:

void test33() {

        List<User> userList = List.of((new User("mail1","adr1")),(new User("mail2","a2")),(new User("mail1","adr3")),(new User("mail1","adr4")));

        Map<String, String> map = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> c+" - "+d));

        map.forEach((k,v) -> System.out.println(k+ ":"+ v));

        System.out.println(map.getClass().getTypeName());

       

        Map<String, String> map2 = userList.stream().collect(Collectors.toMap(a -> a.getEmail(), b -> b.getAddr(), (c,d) -> (c+" - "+d), TreeMap::new));

        map2.forEach((k,v) -> System.out.println(k+ ":"+ v));

        System.out.println(map2.getClass().getTypeName());

    }

执行结果:

mail2:a2

mail1:adr1 - adr3 - adr4

java.util.HashMap

mail1:adr1 - adr3 - adr4

mail2:a2

java.util.TreeMap


http://www.niftyadmin.cn/n/928486.html

相关文章

学习笔记之三张图读懂机器学习 :基本概念、五大流派与九种常见算法 - 超级数学建模...

三张图读懂机器学习 &#xff1a;基本概念、五大流派与九种常见算法 - 超级数学建模 https://mp.weixin.qq.com/s/qiQz1FpP0FHzo-cXKTBb8w 机器学习正在进步&#xff0c;我们似乎正在不断接近我们心中的人工智能目标。语音识别、图像检测、机器翻译、风格迁移等技术已经在我们的…

C#中多线程中变量研究

今天在知乎上看到一个问题【为什么在同一进程中创建不同线程&#xff0c;但线程各自的变量无法在线程间互相访问&#xff1f;】。在多线程中&#xff0c;每个线程都是独立运行的&#xff0c;不同的线程有可能是同一段代码&#xff0c;但不会是同一作用域&#xff0c;所以不会共…

stream.allMatch

boolean allMatch​(Predicate<? super T> predicate) 字面意思就是全部匹配。作用就是定义一个函数参数对集合中全部元素进行计算&#xff0c;如果返回结果都是true那最终结果为true&#xff08;还有一种情况就是集合元素为空也返回true&#xff09;&#xff0c;如果有…

Java消息队列三道面试题详解!

面试题为什么使用消息队列&#xff1f;消息队列有什么优点和缺点&#xff1f;Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别&#xff0c;以及适合哪些场景&#xff1f;面试官心理分析其实面试官主要是想看看&#xff1a;第一&#xff0c;你知不知道你们系统里为什么要用消…

Tensorflow小技巧:TF_CPP_MIN_LOG_LEVEL

#pythonimport os import tensorflow as tf os.environ[TF_CPP_MIN_LOG_LEVEL] 2 # or any {0, 1, 3} #C: (In Terminal)export TF_CPP_MIN_LOG_LEVEL2 TF_CPP_MIN_LOG_LEVEL默认值为 0 (显示所有logs)&#xff0c;设置为 1 隐藏 INFO logs, 2 额外隐藏WARNING logs, 设置为3…

Stream.anyMatch

boolean anyMatch​(Predicate<? super T> predicate) 很容易理解&#xff0c;即是有一个或一个以上的元素满足函数参数计算结果为true那整个方法返回值为true。 看例子&#xff1a; void stream_anyMatch() {List<Integer> list List.of(2,5,8,9,4,20,11,43,…

PostgreSQL 优化器代码概览

为什么80%的码农都做不了架构师&#xff1f;>>> 简介 PostgreSQL 的开发源自上世纪80年代&#xff0c;它最初是 Michael Stonebraker 等人在美国国防部支持下创建的POSTGRE项目。上世纪末&#xff0c;Andrew Yu 等人在它上面搭建了第一个SQL Parser&#xff0c;这个…

1-1.go开发工具安装

(1) (2) bin&#xff1a;go的可执行文件 src&#xff1a;go的源代码 (3)安装开发工具 安装:goland-2018.1.1.exe 将.jar文件复制到工具的bin目录下用记事本打开“goland.exe.vmoptions”和“goland64.exe.vmoptions”这两个文件&#xff0c;在后面添加破解文件的路径-javaagent…