Java 用流访问每个流中的元素替换增强的 for 循环
Java replace enhanced for loop with stream accessing elements from each stream
第一次问这么简单的问题..
我有一些包含嵌套列表的对象。我通常会使用嵌套的 for 循环来对这些进行任何转换,但我热衷于探索 Java8 Streams。本质上,我正在尝试创建一个输出对象,该对象将由每个嵌套列表中访问的字段组成。
我在下面分享了一个非常简单的示例,以及我通常如何使用增强的 for 循环来执行此操作。任何人都可以与我分享我应该如何做这件事吗?此外,如果我们假设这些列表中的一些列表的基数为 [0:M],即它们是可选列表,我将如何使流空安全?
谢谢
// Objects below
class Qualification {
String qualificationName;
String qualificationValue;
}
class Person {
String name;
List<Qualification> qualifications;
}
class Group {
String groupId;
List<Person> people;
}
class Output {
String groupId;
String name;
String qualificationName;
String qualificationValue;
}
下面是我通常如何执行此转换。
// Create empty list to hold the output objects
List<Output> outputList = new ArrayList<Output>();
for(Group g : groups) {
for (Person p : g.getPeople()) {
for (Qualification q : p.getQualifications()) {
// Compose new object and add to list
Output output = new Output();
output.setId(g.getId());
output.setName(p.getName());
output.setQualificationValue(q.getQualificationValue());
output.setQualificationName(q.getQualificationName());
outputList.add(output);
}
}
}
你可以这样做:
List<Output> outputList = groups.stream()
.flatMap(g -> g.getPeople().stream()
.flatMap(p ->
p.getQualifications()
.stream()
.map(q -> {
Output output = new Output();
output.setGroupId(g.getGroupId());
output.setName(p.getName());
output.setQualificationValue(q.getQualificationValue());
output.setQualificationName(q.getQualificationName());
return output;
})
))
.collect(Collectors.toList());
您将不得不使用
filter()
处理空列表,AND
flatMap()
从内部列表创建子流
(我使用了 Lombok 注释;您可以使用常规 getters/setters 和构造函数。)
public class NestedForLoopsIntoStreams{
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Qualification {
String qualificationName;
String qualificationValue;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Person {
String name;
List<Qualification> qualifications;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Group {
String groupId;
List<Person> people;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter @ToString
private static class Output {
String groupId;
String name;
String qualificationName;
String qualificationValue;
}
public static void main( String[] args ){
List<Group> groups = testData();
List<Output> outputs =
groups.stream().filter( g -> g.getPeople() != null )
.flatMap( g -> {
return g.getPeople().stream().filter( p -> p.getQualifications() != null )
.flatMap( p -> {
return p.getQualifications().stream().map( q ->
Output.of( g.groupId, p.name, q.qualificationName, q.qualificationValue )
);
}
);
} ).collect( Collectors.toList() );
outputs.forEach( System.out::println );
}
private static List<Group> testData(){
return Arrays.asList(
Group.of( "1", Arrays.asList(
Person.of( "Person1", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) ),
Person.of( "Person2", Arrays.asList( Qualification.of( "Engg", "MTech" ) ) )
) ),
Group.of( "2", Arrays.asList(
Person.of( "Person3", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) )
) ),
/* Person with no qualication */
Group.of( "3", Arrays.asList(
Person.of( "Person4", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) ),
Person.of( "Person5", null )
) ),
/* No people */
Group.of( "4", null )
);
}
}
运行 这将给出这个输出:
NestedForLoopsIntoStreams.Output(groupId=1, name=Person1, qualificationName=Engg, qualificationValue=BTech)
NestedForLoopsIntoStreams.Output(groupId=1, name=Person2, qualificationName=Engg, qualificationValue=MTech)
NestedForLoopsIntoStreams.Output(groupId=2, name=Person3, qualificationName=Engg, qualificationValue=BTech)
NestedForLoopsIntoStreams.Output(groupId=3, name=Person4, qualificationName=Engg, qualificationValue=BTech)
第一次问这么简单的问题..
我有一些包含嵌套列表的对象。我通常会使用嵌套的 for 循环来对这些进行任何转换,但我热衷于探索 Java8 Streams。本质上,我正在尝试创建一个输出对象,该对象将由每个嵌套列表中访问的字段组成。
我在下面分享了一个非常简单的示例,以及我通常如何使用增强的 for 循环来执行此操作。任何人都可以与我分享我应该如何做这件事吗?此外,如果我们假设这些列表中的一些列表的基数为 [0:M],即它们是可选列表,我将如何使流空安全? 谢谢
// Objects below
class Qualification {
String qualificationName;
String qualificationValue;
}
class Person {
String name;
List<Qualification> qualifications;
}
class Group {
String groupId;
List<Person> people;
}
class Output {
String groupId;
String name;
String qualificationName;
String qualificationValue;
}
下面是我通常如何执行此转换。
// Create empty list to hold the output objects
List<Output> outputList = new ArrayList<Output>();
for(Group g : groups) {
for (Person p : g.getPeople()) {
for (Qualification q : p.getQualifications()) {
// Compose new object and add to list
Output output = new Output();
output.setId(g.getId());
output.setName(p.getName());
output.setQualificationValue(q.getQualificationValue());
output.setQualificationName(q.getQualificationName());
outputList.add(output);
}
}
}
你可以这样做:
List<Output> outputList = groups.stream()
.flatMap(g -> g.getPeople().stream()
.flatMap(p ->
p.getQualifications()
.stream()
.map(q -> {
Output output = new Output();
output.setGroupId(g.getGroupId());
output.setName(p.getName());
output.setQualificationValue(q.getQualificationValue());
output.setQualificationName(q.getQualificationName());
return output;
})
))
.collect(Collectors.toList());
您将不得不使用
filter()
处理空列表,ANDflatMap()
从内部列表创建子流
(我使用了 Lombok 注释;您可以使用常规 getters/setters 和构造函数。)
public class NestedForLoopsIntoStreams{
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Qualification {
String qualificationName;
String qualificationValue;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Person {
String name;
List<Qualification> qualifications;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter
private static class Group {
String groupId;
List<Person> people;
}
@NoArgsConstructor @AllArgsConstructor( staticName = "of" )
@Getter @Setter @ToString
private static class Output {
String groupId;
String name;
String qualificationName;
String qualificationValue;
}
public static void main( String[] args ){
List<Group> groups = testData();
List<Output> outputs =
groups.stream().filter( g -> g.getPeople() != null )
.flatMap( g -> {
return g.getPeople().stream().filter( p -> p.getQualifications() != null )
.flatMap( p -> {
return p.getQualifications().stream().map( q ->
Output.of( g.groupId, p.name, q.qualificationName, q.qualificationValue )
);
}
);
} ).collect( Collectors.toList() );
outputs.forEach( System.out::println );
}
private static List<Group> testData(){
return Arrays.asList(
Group.of( "1", Arrays.asList(
Person.of( "Person1", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) ),
Person.of( "Person2", Arrays.asList( Qualification.of( "Engg", "MTech" ) ) )
) ),
Group.of( "2", Arrays.asList(
Person.of( "Person3", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) )
) ),
/* Person with no qualication */
Group.of( "3", Arrays.asList(
Person.of( "Person4", Arrays.asList( Qualification.of( "Engg", "BTech" ) ) ),
Person.of( "Person5", null )
) ),
/* No people */
Group.of( "4", null )
);
}
}
运行 这将给出这个输出:
NestedForLoopsIntoStreams.Output(groupId=1, name=Person1, qualificationName=Engg, qualificationValue=BTech)
NestedForLoopsIntoStreams.Output(groupId=1, name=Person2, qualificationName=Engg, qualificationValue=MTech)
NestedForLoopsIntoStreams.Output(groupId=2, name=Person3, qualificationName=Engg, qualificationValue=BTech)
NestedForLoopsIntoStreams.Output(groupId=3, name=Person4, qualificationName=Engg, qualificationValue=BTech)