如何从Java Streams中的列表创建映射的键组合
我有一个用户对象列表,我想把它转换成一个以key为FirstName+Last Name,value为ID的映射。有没有办法用Streams来完成这个任务。我尝试了下面的方法,但它不起作用,因为“表达式的目标类型不是函数接口”。我应该使用循环标准来实现这一点吗?非常感谢您的帮助如何从Java Streams中的列表创建映射的键组合,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个用户对象列表,我想把它转换成一个以key为FirstName+Last Name,value为ID的映射。有没有办法用Streams来完成这个任务。我尝试了下面的方法,但它不起作用,因为“表达式的目标类型不是函数接口”。我应该使用循环标准来实现这一点吗?非常感谢您的帮助 List<User> users = userRepo.findAll(); Map<String,Long> userIdMap = users.stream()
List<User> users = userRepo.findAll();
Map<String,Long> userIdMap = users.stream()
.collect(Collectors.toMap(User::getFirstName + "|" + User::getLastName, User::getId));
List users=userRepo.findAll();
Map userIdMap=users.stream()
.collect(Collectors.toMap(User::getFirstName+“|”+User::getLastName,User::getId));
这里,concat方法引用是concat字符串的错误方式。可以这样使用lambda表达式
Map<String,Long> userIdMap =
users.stream()
.collect(Collectors.toMap(u -> u.getFirstName() + "|" + u.getLastName(),
User::getId));
Map userIdMap=
users.stream()
.collect(Collectors.toMap(u->u.getFirstName()+“|”+u.getLastName(),
User::getId));
给出了一个极好的答案。但我的看法略有不同
考虑以下几点:
User u = new User();
Function<User, String> fnc1 = User::getFirstName;
要获得名称,您需要执行以下操作,u
是对所需类的引用。如果您只有一个方法引用,那么它就是这样解决的
name = fnc1.apply(u);
但这并不适用于字符串连接的字符串构造,所以您确实需要这样做
u.getFirstName()
这是lambdau->u.getFirstName()允许的
只需使用lambda而不是方法引用调用该方法
List<User> users = userRepo.findAll();
Map<String,Long> userIdMap =
users.stream()
.collect(Collectors.toMap(u->u.getFirstName() + "|" + u.getLastName(),
User::getId));
List users=userRepo.findAll();
Map userIdMap=
users.stream()
.collect(Collectors.toMap(u->u.getFirstName()+“|”+u.getLastName(),
User::getId));
Type::method
是一个方法引用。在User::getFirstName
的情况下,这已经是User->String
的类型
Java中的函数不是一等公民。没有用于组合或连接它们的运算符。例如,未为用户->字符串(+)用户->字符串定义+
运算符。它是为String+String
定义的
因此,您想要的不是编写裸方法引用,而是创建一个总体类型为User->String
的表达式,而是对实际字符串使用+
操作符
接受用户的lambda需要将其作为第一个参数,并且需要返回一个字符串u->“你好,世界”
就是这样一个lambda。根据需要将其组合在一起,您将得到:
函数userToFullName=u->u.getFirstName()+“|”+u.getLastName()
然后,您可以在收集器内使用该功能:
Function userToFullName=user->user.getFirstName()+“|”+user.getLastName();
Map userIdMap=
users.stream()
.collect(Collectors.toMap(userToFullName,User::getId));
或者,如果不希望在命名变量中显式存储lambda:
Map userIdMap=
users.stream()
.收集(
汤姆(
user->user.getFirstName()+“|”+user.getLastName(),
用户::getId
));
我认为最好不要附加firstName和LastName,而是使用不同的方法,如-
Map<Pair<String, String>,Integer> employeePairs = employees.stream().collect(HashMap<Pair<String, String>, Integer>::new,
(m, c) -> m.put(Pair.of(c.getFirstName(), c.getLastName()), c.employeeId),
(m, u) -> {});
employeePairs.get(Pair.of("firstname", "lastname")); // Access the map in this way
.collect(Collectors.toMap(u->u.getFirstName()+“|”+u.getLastName(),User::getId))代码>很好的答案!唯一的问题是我会调用类似于userToFullName
(强调它是一个映射器)的函数,但这是一个味道的问题…@AndrewTobilko这当然是一个有效的观点,我在这里使用已经存在的方法名称来实现二元性。经过再三考虑,我更喜欢你的建议,并将相应地更改答案。稍有不同,当有一个用toMap
指定的合并函数时,以及在没有该函数的情况下应该注意什么。但是您的代码的输出将不同于使用两个用户的输出,例如“Ishan |”,“Ghosh”
和“Ishan”,“Ghosh”
。
List<User> users = userRepo.findAll();
Map<String,Long> userIdMap =
users.stream()
.collect(Collectors.toMap(u->u.getFirstName() + "|" + u.getLastName(),
User::getId));
Map<Pair<String, String>,Integer> employeePairs = employees.stream().collect(HashMap<Pair<String, String>, Integer>::new,
(m, c) -> m.put(Pair.of(c.getFirstName(), c.getLastName()), c.employeeId),
(m, u) -> {});
employeePairs.get(Pair.of("firstname", "lastname")); // Access the map in this way
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
import org.apache.commons.lang3.tuple.Pair;