使用 forEach 流创建列表列表(嵌套列表),Java 8
stream creating List of List (nested List) using forEach, Java 8
class EntityCompositeId {
private Long firstId;
private Long secondId;
// getter & setter...
}
class EntityComposite {
private EntityCompositeId id;
private String first;
private String second;
// getter & setter...
}
List<EntityComposite> listEntityComposite = ....
Supose this content
1, 1, "firstA", "secondBirdOne"
1, 2, "firstA", "secondBirdTwo"
1, 3, "firstA", "secondBirdThree"
2, 1, "firstB", "secondCatOne"
2, 2, "firstB", "secondCatTwo"
2, 3, "firstB", "secondCatThree"
3, 1, "firstC", "secondDogOne"
3, 2, "firstC", "secondDogTwo"
3, 3, "firstC", "secondDogThree"
Map<Long, List<String>> listOfLists = new HashMap<>();
现在使用我想要填充的流:
1 -> {"secondBirdOne", "secondBirdTwo", "secondBirdThree"}
2 -> {"secondCatOne", "secondCatTwo", "secondCatThree"}
3 -> {"secondDogOne", "secondDogTwo", "secondDogThree"}
我的未完成(这就是问题)代码是:
listEntityComposite.stream()forEach(entityComposite {
// How create a list according entityComposite.getId.getFirstId()?
listOfLists.put(entityComposite.getId.getFirstId(), .... )
});
collect
比 forEach
.
更适合生成输出 Map
的终端操作
您可以将 collect()
与 Collectors.groupingBy
一起使用:
Map<Long, List<String>> listOfLists =
listEntityComposite.stream()
.collect(Collectors.groupingBy(e -> e.getId().getFirstId(),
Collectors.mapping(EntityComposite::getSecond,
Collectors.toList());
Collectors.groupingBy
带有单个参数(仅 e -> e.getId().getFirstId()
)会生成 Map<Long,List<EntityComposite>>
.
链接到它 Collectors.mapping()
根据需要将每个 EntityComposite
实例映射到相应的 getSecond()
String
。
您可以通过多种不同的方法完成手头的任务。
Map<Long, List<String>> map = new HashMap<>();
listEntityComposite.forEach(e -> map.computeIfAbsent(e.getId().getFirstId(),
k -> new ArrayList<>()).add(e.getSecond()));
- 通过
forEach
枚举listEntityComposite
中的元素
- 对于每个元素利用
computeIfAbsent
计算键(即firstId
)和值(即List<String>
)
另一种方法是将 groupingBy
与 mapping
下游收集器一起应用:
Map<Long, List<String>> resultSet = listEntityComposite.stream()
.collect(groupingBy(e -> e.getId().getFirstId(),
mapping(EntityComposite::getSecond, toList())));
- 通过分类函数
e.getId().getFirstId()
对源元素进行分组,然后应用 mapping
下游收集器进一步优化我们的查询。
listEntityComposite.forEach(e -> map.merge(e.getId().getFirstId(),
new ArrayList<>(singletonList(e.getSecond())),
(l, r) -> {l.addAll(r); return l;}));
通过forEach
枚举listEntityComposite
中的元素
对于每个元素利用merge
计算键(即firstId
)和值(即List<String>
)
listEntityComposite.stream()
.collect(toMap(e -> e.getId().getFirstId(),
v -> new ArrayList<>(singletonList(v.getSecond())),
(l, r) -> {l.addAll(r); return l;}));
- 应用
keyMapper
函数 e -> e.getId().getFirstId()
提取映射键。
- 应用
valueMapper
函数 v -> new ArrayList<>(singletonList(v.getSecond()))
来提取地图值。
- 应用
merge
函数 (l, r) -> {l.addAll(r); return l;}
解决按键冲突。
总而言之,forEach
+ computeIfAbsent
方法和 groupingBy
+ mapping
方法是您在这种特定情况下应该偏爱的两种方法,因为它们是更地道。
我建议研究一下 Guava 的 MultiMap,它使您的用例更易于处理(提供大量优化和您以后可能希望获得的额外功能)
编辑:
为什么 Multimap 比使用 computeIfAbsent 方法更有意义的一个例子:
1. 每个键都有一个一定大小的列表,如果以后想得到"total"大小怎么办?您必须创建一些逻辑才能以良好的性能实现这一点(或使用采用 O(keys) 的方法)
2. 目前你只是把东西放到地图上,但是如果你以后想把东西从地图上移除怎么办?您将需要编写一些样板代码(很容易出错)以确保删除值不会导致内存泄漏
使用多图还有其他好处,但这只是两个易于解释的好处。
编辑 2:
使用您的输入的示例:
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
public class Example {
public static class EntityCompositeId {
@Override
public String toString() {
return "EntityCompositeId [firstId=" + firstId + ", secondId=" + secondId + "]";
}
public EntityCompositeId(Long firstId, Long secondId) {
super();
this.firstId = firstId;
this.secondId = secondId;
}
private Long firstId;
public Long getFirstId() {
return firstId;
}
private Long secondId;
}
public static class EntityComposite {
@Override
public String toString() {
return "EntityComposite [id=" + id + ", first=" + first + ", second=" + second + "]";
}
public EntityComposite(EntityCompositeId id, String first, String second) {
super();
this.id = id;
this.first = first;
this.second = second;
}
private EntityCompositeId id;
public EntityCompositeId getId() {
return id;
}
private String first;
private String second;
}
public static void main(String[] args) {
List<EntityComposite> listEntityComposite = Arrays.asList(
new EntityComposite(new EntityCompositeId(1l, 1l), "firstA", "secondBirdOne"),
new EntityComposite(new EntityCompositeId(1l, 2l), "firstA", "secondBirdTwo"),
new EntityComposite(new EntityCompositeId(1l, 3l), "firstA", "secondBirdThree"),
new EntityComposite(new EntityCompositeId(2l, 1l), "firstB", "secondCatOne"),
new EntityComposite(new EntityCompositeId(2l, 2l), "firstB", "secondCatTwo"),
new EntityComposite(new EntityCompositeId(2l, 3l), "firstB", "secondCatThree"),
new EntityComposite(new EntityCompositeId(3l, 1l), "firstC", "secondDogOne"),
new EntityComposite(new EntityCompositeId(3l, 2l), "firstC", "secondDogTwo"),
new EntityComposite(new EntityCompositeId(3l, 3l), "firstC", "secondDogThree"));
ListMultimap<Long, EntityComposite> map = ArrayListMultimap.create();
listEntityComposite.forEach(entityComposite -> map.put(entityComposite.getId().getFirstId(), entityComposite));
map.keySet().forEach(key -> System.out.println(map.get(key)));
}
}
产生以下输出:
[EntityComposite [id=EntityCompositeId [firstId=1, secondId=1], first=firstA, second=secondBirdOne], EntityComposite [id=EntityCompositeId [firstId=1, secondId=2], first=firstA, second=secondBirdTwo], EntityComposite [id=EntityCompositeId [firstId=1, secondId=3], first=firstA, second=secondBirdThree]]
[EntityComposite [id=EntityCompositeId [firstId=2, secondId=1], first=firstB, second=secondCatOne], EntityComposite [id=EntityCompositeId [firstId=2, secondId=2], first=firstB, second=secondCatTwo], EntityComposite [id=EntityCompositeId [firstId=2, secondId=3], first=firstB, second=secondCatThree]]
[EntityComposite [id=EntityCompositeId [firstId=3, secondId=1], first=firstC, second=secondDogOne], EntityComposite [id=EntityCompositeId [firstId=3, secondId=2], first=firstC, second=secondDogTwo], EntityComposite [id=EntityCompositeId [firstId=3, secondId=3], first=firstC, second=secondDogThree]]
class EntityCompositeId {
private Long firstId;
private Long secondId;
// getter & setter...
}
class EntityComposite {
private EntityCompositeId id;
private String first;
private String second;
// getter & setter...
}
List<EntityComposite> listEntityComposite = ....
Supose this content
1, 1, "firstA", "secondBirdOne"
1, 2, "firstA", "secondBirdTwo"
1, 3, "firstA", "secondBirdThree"
2, 1, "firstB", "secondCatOne"
2, 2, "firstB", "secondCatTwo"
2, 3, "firstB", "secondCatThree"
3, 1, "firstC", "secondDogOne"
3, 2, "firstC", "secondDogTwo"
3, 3, "firstC", "secondDogThree"
Map<Long, List<String>> listOfLists = new HashMap<>();
现在使用我想要填充的流:
1 -> {"secondBirdOne", "secondBirdTwo", "secondBirdThree"}
2 -> {"secondCatOne", "secondCatTwo", "secondCatThree"}
3 -> {"secondDogOne", "secondDogTwo", "secondDogThree"}
我的未完成(这就是问题)代码是:
listEntityComposite.stream()forEach(entityComposite {
// How create a list according entityComposite.getId.getFirstId()?
listOfLists.put(entityComposite.getId.getFirstId(), .... )
});
collect
比 forEach
.
Map
的终端操作
您可以将 collect()
与 Collectors.groupingBy
一起使用:
Map<Long, List<String>> listOfLists =
listEntityComposite.stream()
.collect(Collectors.groupingBy(e -> e.getId().getFirstId(),
Collectors.mapping(EntityComposite::getSecond,
Collectors.toList());
Collectors.groupingBy
带有单个参数(仅 e -> e.getId().getFirstId()
)会生成 Map<Long,List<EntityComposite>>
.
链接到它 Collectors.mapping()
根据需要将每个 EntityComposite
实例映射到相应的 getSecond()
String
。
您可以通过多种不同的方法完成手头的任务。
Map<Long, List<String>> map = new HashMap<>();
listEntityComposite.forEach(e -> map.computeIfAbsent(e.getId().getFirstId(),
k -> new ArrayList<>()).add(e.getSecond()));
- 通过
forEach
枚举 - 对于每个元素利用
computeIfAbsent
计算键(即firstId
)和值(即List<String>
)
listEntityComposite
中的元素
另一种方法是将 groupingBy
与 mapping
下游收集器一起应用:
Map<Long, List<String>> resultSet = listEntityComposite.stream()
.collect(groupingBy(e -> e.getId().getFirstId(),
mapping(EntityComposite::getSecond, toList())));
- 通过分类函数
e.getId().getFirstId()
对源元素进行分组,然后应用mapping
下游收集器进一步优化我们的查询。
listEntityComposite.forEach(e -> map.merge(e.getId().getFirstId(),
new ArrayList<>(singletonList(e.getSecond())),
(l, r) -> {l.addAll(r); return l;}));
通过
forEach
枚举对于每个元素利用
merge
计算键(即firstId
)和值(即List<String>
)
listEntityComposite
中的元素
listEntityComposite.stream()
.collect(toMap(e -> e.getId().getFirstId(),
v -> new ArrayList<>(singletonList(v.getSecond())),
(l, r) -> {l.addAll(r); return l;}));
- 应用
keyMapper
函数e -> e.getId().getFirstId()
提取映射键。 - 应用
valueMapper
函数v -> new ArrayList<>(singletonList(v.getSecond()))
来提取地图值。 - 应用
merge
函数(l, r) -> {l.addAll(r); return l;}
解决按键冲突。
总而言之,forEach
+ computeIfAbsent
方法和 groupingBy
+ mapping
方法是您在这种特定情况下应该偏爱的两种方法,因为它们是更地道。
我建议研究一下 Guava 的 MultiMap,它使您的用例更易于处理(提供大量优化和您以后可能希望获得的额外功能)
编辑: 为什么 Multimap 比使用 computeIfAbsent 方法更有意义的一个例子: 1. 每个键都有一个一定大小的列表,如果以后想得到"total"大小怎么办?您必须创建一些逻辑才能以良好的性能实现这一点(或使用采用 O(keys) 的方法) 2. 目前你只是把东西放到地图上,但是如果你以后想把东西从地图上移除怎么办?您将需要编写一些样板代码(很容易出错)以确保删除值不会导致内存泄漏
使用多图还有其他好处,但这只是两个易于解释的好处。
编辑 2: 使用您的输入的示例:
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
public class Example {
public static class EntityCompositeId {
@Override
public String toString() {
return "EntityCompositeId [firstId=" + firstId + ", secondId=" + secondId + "]";
}
public EntityCompositeId(Long firstId, Long secondId) {
super();
this.firstId = firstId;
this.secondId = secondId;
}
private Long firstId;
public Long getFirstId() {
return firstId;
}
private Long secondId;
}
public static class EntityComposite {
@Override
public String toString() {
return "EntityComposite [id=" + id + ", first=" + first + ", second=" + second + "]";
}
public EntityComposite(EntityCompositeId id, String first, String second) {
super();
this.id = id;
this.first = first;
this.second = second;
}
private EntityCompositeId id;
public EntityCompositeId getId() {
return id;
}
private String first;
private String second;
}
public static void main(String[] args) {
List<EntityComposite> listEntityComposite = Arrays.asList(
new EntityComposite(new EntityCompositeId(1l, 1l), "firstA", "secondBirdOne"),
new EntityComposite(new EntityCompositeId(1l, 2l), "firstA", "secondBirdTwo"),
new EntityComposite(new EntityCompositeId(1l, 3l), "firstA", "secondBirdThree"),
new EntityComposite(new EntityCompositeId(2l, 1l), "firstB", "secondCatOne"),
new EntityComposite(new EntityCompositeId(2l, 2l), "firstB", "secondCatTwo"),
new EntityComposite(new EntityCompositeId(2l, 3l), "firstB", "secondCatThree"),
new EntityComposite(new EntityCompositeId(3l, 1l), "firstC", "secondDogOne"),
new EntityComposite(new EntityCompositeId(3l, 2l), "firstC", "secondDogTwo"),
new EntityComposite(new EntityCompositeId(3l, 3l), "firstC", "secondDogThree"));
ListMultimap<Long, EntityComposite> map = ArrayListMultimap.create();
listEntityComposite.forEach(entityComposite -> map.put(entityComposite.getId().getFirstId(), entityComposite));
map.keySet().forEach(key -> System.out.println(map.get(key)));
}
}
产生以下输出:
[EntityComposite [id=EntityCompositeId [firstId=1, secondId=1], first=firstA, second=secondBirdOne], EntityComposite [id=EntityCompositeId [firstId=1, secondId=2], first=firstA, second=secondBirdTwo], EntityComposite [id=EntityCompositeId [firstId=1, secondId=3], first=firstA, second=secondBirdThree]]
[EntityComposite [id=EntityCompositeId [firstId=2, secondId=1], first=firstB, second=secondCatOne], EntityComposite [id=EntityCompositeId [firstId=2, secondId=2], first=firstB, second=secondCatTwo], EntityComposite [id=EntityCompositeId [firstId=2, secondId=3], first=firstB, second=secondCatThree]]
[EntityComposite [id=EntityCompositeId [firstId=3, secondId=1], first=firstC, second=secondDogOne], EntityComposite [id=EntityCompositeId [firstId=3, secondId=2], first=firstC, second=secondDogTwo], EntityComposite [id=EntityCompositeId [firstId=3, secondId=3], first=firstC, second=secondDogThree]]