Java 如何在匿名函数中使用计数器?

Java 如何在匿名函数中使用计数器?,java,lambda,counter,final,Java,Lambda,Counter,Final,使用Java8,我希望将两个集合合并到集合中:一个集合是Java.util.List;另一个是com.fasterxml.jackson.databind.node.ArrayNode 以下是一种非Java 8的处理方法: private void mergeMemberAndRelationshipData(final List<JsonNode> members, final ArrayNode relationships) { assert members != nu

使用Java8,我希望将两个集合合并到集合中:一个集合是
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);
        }
    }
}
或者我可以使用一个
原子整数

AtomicInteger i = new AtomicInteger(0);
...
final ObjectNode relationship = (ObjectNode) relationships.get(i.getAndIncrement());
但这是对原子整数的误用;这意味着线程之间的共享值。不完全是这里发生的事情,它的方式太重,这是一个适当的使用(在我看来,请随意不同意我)

因此,这是一件非常常见的事情(链接两个有序列表并对其元素进行操作)。Java 8之前的版本非常简单(技术上仍然如此,但我相信你们这些书呆子明白我的意思)。有没有一种Java-8-ey方法可以使用streams来实现这一点


对于我工作的上下文,我们使用微服务体系结构方法。这意味着我们有一组服务负责一组离散的、封装的职责(例如,MemberService处理成员CRUD,CompanyService处理公司CRUD)。最重要的是,我们有一个编排/身份验证/授权服务,可以进行这些不同的调用,然后将它们缝合在一起。所以,在我粘贴的方法中,这是编排层,在这里我得到两个数据集,现在我想将它们合并在一起。这就是我没有LinkedList或其他类似解决方案的原因。

您不能为此使用方法的局部变量。但是,您可以简单地使用类字段:

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++);

        ...
    });
}
private int i=0;
私有void mergeMemberAndRelationshipData(最终列表成员、最终ArrayNode关系){
断言成员!=null:“成员不能为null”;
断言关系!=null:“关系不能为null”;
members.stream().forEach(成员->{
final ObjectNode relationship=(ObjectNode)relationships.get(i++);
...
});
}

这不是线程安全的,因此您需要确保,如果您有线程,每个线程都在使用它自己的此类实例,或者您有适当的锁定机制。

使用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(最终列表成员、最终ArrayNode关系)
{       
List relationshipList=members.stream()
.filter(x->x!=null)
.map(x->//构建单个关系对象)
.collect(Collectors.toList());
relationshipList.forEach(x->//添加到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
                });
    }
private void mergeMemberAndRelationshipData(最终列表成员、最终ArrayNode关系)
{       
IntStream.range(0,members.size())
.forEach(i->
{ 
if(members.get(i)!=null)
//添加数据
其他的
//执行日志记录
});
}

您想要寻找拉链。Java最初内置了一个zip实用程序,但后来被删除了。下面是一个使用流压缩的stackoverflow响应,示例实现为:

除此之外,为了避免在外部保留索引,您可以使用
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);
final List a=Arrays.asList(“a”、“b”、“c”);
最终列表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);

为什么不创建一个可变整数包装器呢?一个
新的int[1]
就足够了。这是另一个选项,但每次我想在流循环中使用计数器时,似乎都有很多样板文件。当使用stream.foreach最终取代for each循环时,在我看来,似乎有一种简单的、非样板的方法来处理这种情况。我尝试过这种方法,但它一直在崩溃。例如,虽然我可以在filter函数中添加logging,但我会丢失两个列表之间的一对一关系,从而破坏它们的链接。这里我几乎需要某种类型的
,但java拒绝实现一种:(啊,那么你基本上是将这两个对象视为一个非官方的链表?让我看看我能想出什么。我添加了一个替代解决方案。希望新的解决方案能与你的用例相匹配。我使用数组破解。这是最简单的解决方法。在我看来也是如此,它是如此丑陋,是数组的一个混蛋化。另外,它是它欺骗了编译器的安全检查,这也是我不喜欢它的另一个原因,尽管它可以工作。我喜欢下面jay的解决方案,并将继续使用它,因为它看起来很有希望。此外,它是一个使用java 8 libs的函数式编程解决方案,这也是我所追求的。我想成为函数式的,并学习这些新的,尽管很奇怪的编程方法解决共同问题。
    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
                });
    }
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);