使用Java 8,我想要两个组合到集合:一个集合是java.util.List
;另一个是com.fasterxml.jackson.databind.node.ArrayNode
。
这是一种非Java 8处理方式:
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships) {
assert members != null : "members cannot be null";
assert relationships != null : "relationships cannot be null";
for (int i = 0; i < members.size(); i++) {
final ObjectNode relationship = (ObjectNode) relationships.get(i);
final JsonNode member = members.get(i);
if (member != null && !member.hasNonNull(ExceptionMapper.errorCodeStr)) {
relationship.put(FIRST_NAME, this.jsonHelpers.safeGetString(member, FIRST_NAME));
relationship.put(LAST_NAME, this.jsonHelpers.safeGetString(member, LAST_NAME));
relationship.put(EMAIL, this.jsonHelpers.safeGetString(member, EMAIL));
relationship.put(MEMBER_SINCE, this.jsonHelpers.safeGetString(member, MEMBER_SINCE));
} else {
LOGGER.error("No corresponding Member, {}, found for Relationship: {}", member, relationship);
}
}
}
我想流。我喜欢溪流。好吧,那么,让我们试一试:
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships) {
assert members != null : "members cannot be null";
assert relationships != null : "relationships cannot be null";
int i = 0;
members.stream().forEach(member -> {
final ObjectNode relationship = (ObjectNode) relationships.get(i++);
if (member != null) {
relationship.put(FIRST_NAME, this.jsonHelpers.safeGetString(member, FIRST_NAME));
relationship.put(LAST_NAME, this.jsonHelpers.safeGetString(member, LAST_NAME));
relationship.put(EMAIL, this.jsonHelpers.safeGetString(member, EMAIL));
relationship.put(MEMBER_SINCE, this.jsonHelpers.safeGetString(member, MEMBER_SINCE));
} else {
LOGGER.warn("No corresponding member found for relationship: {}", relationship);
}
});
}
但不,那不会起作用:Local variable i defined in an enclosing scope must be final or effectively final
。是的,这是有道理的。有点。
好吧,所以我想要流式传输一个集合A
,并为A
中的每个对象,对集合中的相应对象B
执行一些操作。我需要知道索引才能做到这一点。
如何在匿名函数内部使用在匿名函数范围之外声明的计数器?
我可以用创造性的创造性方式解决这个问题:
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships) {
assert members != null : "members cannot be null";
assert relationships != null : "relationships cannot be null";
int[] i = new int[1];
i[0] = 0;
members.stream().forEach(member -> {
final ObjectNode relationship = (ObjectNode) relationships.get(i[0]);
i[0] = i[0]++;
if (member != null) {
relationship.put(FIRST_NAME, this.jsonHelpers.safeGetString(member, FIRST_NAME));
relationship.put(LAST_NAME, this.jsonHelpers.safeGetString(member, LAST_NAME));
relationship.put(EMAIL, this.jsonHelpers.safeGetString(member, EMAIL));
relationship.put(MEMBER_SINCE, this.jsonHelpers.safeGetString(member, MEMBER_SINCE));
} else {
LOGGER.warn("No correspodning member foudn for relationship: {}", relationship);
}
});
}
或者我可以使用AtomicInteger
:
AtomicInteger i = new AtomicInteger(0);
...
final ObjectNode relationship = (ObjectNode) relationships.get(i.getAndIncrement());
但这是对AtomicInteger
的误用;这意味着线程之间的共享价值。不完全是在这里发生的事情,而且它的重量级太重了,这是一个合适的用途(在我看来,请随意不同意我)。
因此,这是一个非常常见的事情(链接两个有序列表并对其元素进行操作)。它在Java 8之前非常容易(技术上仍然如此,但是你的小学生明白我的观点,我确定)。是否有使用流来实现此目的的Java-8-ey方法?
对于我工作的上下文,我们使用微服务架构方法。这意味着我们有一堆服务负责一组离散的,封装的职责(例如,MemberService处理成员CRUD,而CompanyService处理公司CRUD)。最重要的是,我们有一个编排/身份验证/授权服务,可以进行这些不同的调用,然后将它们拼接在一起。因此,在我粘贴的方法中,这是业务流程层,我获取了两个数据集,现在我想将它们合并在一起。这就是我没有LinkedList或其他类似解决方案的原因。
答案 0 :(得分:2)
使用Streams可以让您更多地使用函数式编程范例。从这个范例来看,最好在集合上使用Map函数,而不是改变外部状态。
这不是一个精确的重构(例如,没有空成员的日志记录),但它可能是一个伪代码解决方案,可以让你朝着你想要的方向前进。
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships)
{
List<...{SomeJsonObject}...> relationshipList = members.stream()
.filter(x -> x != null)
.map(x -> //build individual relationship object)
.collect(Collectors.toList());
relationshipList.forEach(x -> //add to ArrayNode);
}
如果您需要在步骤中迭代这两个集合,另一种方法是:
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships)
{
IntStream.range(0, members.size())
.forEach(i ->
{
if (members.get(i) != null)
//add data
else
//perform logging
});
}
答案 1 :(得分:2)
你想寻找拉链。 Java最初内置了一个zip实用程序,但它已被删除。以下是使用示例实现的流进行压缩的过去stackoverflow响应:Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)。
除此之外,为了避免在外部保留索引,您可以使用IntStream
:
final List<String> a = Arrays.asList("a", "b", "c");
final List<String> b = Arrays.asList("1", "2", "3");
IntStream.range(0, Math.min(a.size(), b.size()))
.mapToObj(i -> a.get(i) + "-" + b.get(i))
.forEach(System.out::println);
答案 2 :(得分:0)
您不能为此方法使用本地变量。但是,您可以简单地使用类字段:
private int i = 0;
private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships) {
assert members != null : "members cannot be null";
assert relationships != null : "relationships cannot be null";
members.stream().forEach(member -> {
final ObjectNode relationship = (ObjectNode) relationships.get(i++);
...
});
}
这不是线程安全的,所以你需要确保如果你有线程,每个线程都在使用它自己的这个类的实例,或者你有适当的锁定机制。