如何从Java 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()

我有一个用户对象列表,我想把它转换成一个以key为FirstName+Last Name,value为ID的映射。有没有办法用Streams来完成这个任务。我尝试了下面的方法,但它不起作用,因为“表达式的目标类型不是函数接口”。我应该使用循环标准来实现这一点吗?非常感谢您的帮助

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()
这是lambda
u->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;