将具有多个属性的对象映射到另一个对象,然后收集到列表
Map an object with multiple properties to another and then collect to list
我有一个这样的对象:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private String name;
private String lastName;
}
还有一个,我们称它为:
@Data
@AllArgsConstructor
@NoArgsConstructor
class DBPerson {
private String name;
private String lastName;
}
假设两个对象都有一个带有 name
和 lastName
的构造函数以及它们各自的 getter 和 setter,我正在使用 lombok
List<DBPerson> dbPersons = new ArrayList();
dbPersons.add(new DBPerson("Harry", "Potter"));
dbPersons.add(new DBPerson("Hermione", "Granger"));
dbPersons.add(new DBPerson("Ronald", "Weasley"));
我需要将 List<DBPerson>
转换为 List<Person>
,所以我尝试了这种方式:
dbPersons.stream()
.map(DBPerson::getName)
.map(Person::new)
.collect(Collectors.toList());
这显然在 new
上给我一个错误,因为在 Person
class
上没有带有单个 String
的构造函数
我如何映射 DBPerson
的两个属性以创建一个新的 Person
,然后将所有这些都收集到 List<Person>
中?
我试过 .forEach
,但我不确定它是否是最佳解决方案,所以如果有另一种使用 Stream API 的方法,我将不胜感激更好的解决方案,否则我将不得不坚持 .forEach
.
我找到了其他使用 flatMap
的解决方案,但这些解决方案用于将 name
和 lastName
连接成一个 String
,这不是我想要的。
tl;博士
向第二个 class 添加一个构造函数,该构造函数采用第一个 class 类型的参数。将 Stream#map
与该构造函数的方法引用一起使用,并收集第二个 class.
的新实例
personXes.stream().map( PersonY :: new ).toList();
Lambda 函数
与其对 getter 使用方法引用,不如编写 lambda 函数来生成新对象。
为简洁起见,我们使用 Java 16+ records 功能。
package work.basil.mix;
public record PersonX( String firstName , String lastName ) { }
package work.basil.mix;
public record PersonY( String firstName , String lastName ) { }
获取一些示例数据。
List < PersonX > xList =
List.of(
new PersonX( "Harry" , "Potter" ) ,
new PersonX( "Hermione" , "Granger" ) ,
new PersonX( "Ronald" , "Weasley" )
);
创建该列表中元素的流。对于每个 PersonX
个对象,我们需要生成一个 PersonY
个对象。对于这样的转换,请使用 Stream#map
。 map
函数的结果必须与我们新集合的类型相匹配。在我们的例子中,新集合是 List< PersonY >
。所以我们的转换 map
函数必须产生一个 PersonY
对象。
最后,我们通过调用 .toList
将每个新产生的 PersonY
收集到一个不可修改的列表中。在Java 16之前,必须使用更冗长的.collect( Collectors.toList() )
.
List < PersonY > yList = xList.stream().map( personX -> new PersonY( personX.firstName() , personX.lastName() ) ).toList() ;
采用交替格式。
List < PersonY > yList =
xList
.stream()
.map(
personX -> new PersonY( personX.firstName() , personX.lastName() )
)
.toList();
当运行.
yList = [PersonY[firstName=Harry, lastName=Potter], PersonY[firstName=Hermione, lastName=Granger], PersonY[firstName=Ronald, lastName=Weasley]]
备用构造函数
另一种方法是向第二个 class 添加构造函数,将第一个 class 的对象作为参数。然后构造函数从第一个 class 的现有对象中提取必要的数据来构造第二个 class.
的对象
如果您经常以持续的方式进行这种转换,那么这种方法很有意义。
package work.basil.mix;
public record PersonY( String firstName , String lastName ) {
public PersonY ( PersonX personX ) {
this( personX.firstName() , personX.lastName() );
}
}
现在我们可以简化上面看到的代码。
List < PersonY > yList = xList.stream().map( personX -> new PersonY( personX ) ).toList();
我们可以通过使用构造函数的方法引用来进一步简化:PersonY :: new
。每个 personX
对象都将隐式传递给构造函数。
下一行代码与上一行代码完全相同,只是更短,而不是更好。在这两种情况下,第一个 class 的每个流对象都被传递给第二个 class.
的构造函数
List < PersonY > yList = xList.stream().map( PersonY :: new ).toList();
在java8
Function<DBPerson, Person> toPersonMapper =
dbPerson -> new Person(dbPerson.getName(), dbPerson.getLastName());
List<Person> personList =
dbPersonList
.stream()
.map(toPersonMapper)
.collect(Collectors.toList());
我有一个这样的对象:
@Data
@AllArgsConstructor
@NoArgsConstructor
class Person {
private String name;
private String lastName;
}
还有一个,我们称它为:
@Data
@AllArgsConstructor
@NoArgsConstructor
class DBPerson {
private String name;
private String lastName;
}
假设两个对象都有一个带有 name
和 lastName
的构造函数以及它们各自的 getter 和 setter,我正在使用 lombok
List<DBPerson> dbPersons = new ArrayList();
dbPersons.add(new DBPerson("Harry", "Potter"));
dbPersons.add(new DBPerson("Hermione", "Granger"));
dbPersons.add(new DBPerson("Ronald", "Weasley"));
我需要将 List<DBPerson>
转换为 List<Person>
,所以我尝试了这种方式:
dbPersons.stream()
.map(DBPerson::getName)
.map(Person::new)
.collect(Collectors.toList());
这显然在 new
上给我一个错误,因为在 Person
class
String
的构造函数
我如何映射 DBPerson
的两个属性以创建一个新的 Person
,然后将所有这些都收集到 List<Person>
中?
我试过 .forEach
,但我不确定它是否是最佳解决方案,所以如果有另一种使用 Stream API 的方法,我将不胜感激更好的解决方案,否则我将不得不坚持 .forEach
.
我找到了其他使用 flatMap
的解决方案,但这些解决方案用于将 name
和 lastName
连接成一个 String
,这不是我想要的。
tl;博士
向第二个 class 添加一个构造函数,该构造函数采用第一个 class 类型的参数。将 Stream#map
与该构造函数的方法引用一起使用,并收集第二个 class.
personXes.stream().map( PersonY :: new ).toList();
Lambda 函数
与其对 getter 使用方法引用,不如编写 lambda 函数来生成新对象。
为简洁起见,我们使用 Java 16+ records 功能。
package work.basil.mix;
public record PersonX( String firstName , String lastName ) { }
package work.basil.mix;
public record PersonY( String firstName , String lastName ) { }
获取一些示例数据。
List < PersonX > xList =
List.of(
new PersonX( "Harry" , "Potter" ) ,
new PersonX( "Hermione" , "Granger" ) ,
new PersonX( "Ronald" , "Weasley" )
);
创建该列表中元素的流。对于每个 PersonX
个对象,我们需要生成一个 PersonY
个对象。对于这样的转换,请使用 Stream#map
。 map
函数的结果必须与我们新集合的类型相匹配。在我们的例子中,新集合是 List< PersonY >
。所以我们的转换 map
函数必须产生一个 PersonY
对象。
最后,我们通过调用 .toList
将每个新产生的 PersonY
收集到一个不可修改的列表中。在Java 16之前,必须使用更冗长的.collect( Collectors.toList() )
.
List < PersonY > yList = xList.stream().map( personX -> new PersonY( personX.firstName() , personX.lastName() ) ).toList() ;
采用交替格式。
List < PersonY > yList =
xList
.stream()
.map(
personX -> new PersonY( personX.firstName() , personX.lastName() )
)
.toList();
当运行.
yList = [PersonY[firstName=Harry, lastName=Potter], PersonY[firstName=Hermione, lastName=Granger], PersonY[firstName=Ronald, lastName=Weasley]]
备用构造函数
另一种方法是向第二个 class 添加构造函数,将第一个 class 的对象作为参数。然后构造函数从第一个 class 的现有对象中提取必要的数据来构造第二个 class.
的对象如果您经常以持续的方式进行这种转换,那么这种方法很有意义。
package work.basil.mix;
public record PersonY( String firstName , String lastName ) {
public PersonY ( PersonX personX ) {
this( personX.firstName() , personX.lastName() );
}
}
现在我们可以简化上面看到的代码。
List < PersonY > yList = xList.stream().map( personX -> new PersonY( personX ) ).toList();
我们可以通过使用构造函数的方法引用来进一步简化:PersonY :: new
。每个 personX
对象都将隐式传递给构造函数。
下一行代码与上一行代码完全相同,只是更短,而不是更好。在这两种情况下,第一个 class 的每个流对象都被传递给第二个 class.
的构造函数List < PersonY > yList = xList.stream().map( PersonY :: new ).toList();
在java8
Function<DBPerson, Person> toPersonMapper =
dbPerson -> new Person(dbPerson.getName(), dbPerson.getLastName());
List<Person> personList =
dbPersonList
.stream()
.map(toPersonMapper)
.collect(Collectors.toList());