从流中删除 AtomicInteger 计数器

Posted

技术标签:

【中文标题】从流中删除 AtomicInteger 计数器【英文标题】:Remove AtomicInteger counter from stream 【发布时间】:2021-08-15 19:06:25 【问题描述】:

是否可以使用下面的代码实现相同的功能,但不使用 AtomicInteger 计数器,或者事实上根本没有计数器?这段代码控制了我的项目前端某些区域可以完成的顺序。如果isAutomaticDataEnabled(name)true,那么来自dataList 的第一个元素——dataList 中的IData 元素被转换为Data,然后一个Data 列表作为HTTP 响应发送回前端——必须进行处理然后只有在它被处理后,dataList 中的第二个项目才可用于处理和修改,因此我添加了该计数器。但我想保持流,但以某种方式达到相同的结果,至于我什么时候有计数器。是否可以以某种方式将其删除并修改流以使我不改变我的功能并且不返回使用传统的 for 循环?

谢谢

public List<Data> toData(List<Idata> dataList, String name) 
    AtomicInteger counter = new AtomicInteger(0);
    List<Data> data= dataList.stream().sorted().map(input -> 
        if (input == null) 
            throw new IllegalArgumentException("input cannot be null for IData");
        
        if (counter.get() == 0 && !input.getStatus().equals(DataStatus.COMPLETE)) 
            counter.compareAndSet(counter.get(), counter.get() + 1);
            return populateDataFields(input,true); //JUST a method that populates fiedls
        
        if (isAutomaticDataEnabled(name)) 
            return populateDataFields(input,false);
        
        return populateDataFields(input,true);
    ).collect(Collectors.toList());
    counter.set(0);
    return data;

【问题讨论】:

好像你有一个状态机。状态0 有点“准备处理”,非零是“块未准备好” 有点。 Data 对象有一个 canBeCompleted 布尔字段,仅当前一个 Data 对象的状态为 COMPLETED 时才设置为 true。如果启用了严格的签名顺序,那么第一次访问此方法时,只有列表中的顶部元素分配有 canBeCompleted=true。然后如果我们在前端完成它,那么列表中的下一个元素将被赋值为 true 等等 是否可以修改这段代码,而不会失去现代java 8+风格的使用? 老实说,这种蒸汽实现非常难以理解并且违反直觉。我认为您应该(用文字)定义您的实际目标是什么。这段代码看起来对底层问题的理解不够好,无法编写干净的实现。为什么 populateDataFields 被称为 3x 并带有不同的参数?为什么要使用流来解决(也许)它们不适合的问题?您能否在初始阶段处理“第一个”元素,然后在第二阶段处理其余元素?不需要在方法结束时重置计数器。 对不起,您的解释难以理解。您在什么时候发送 HTTP 响应,它与您显示的代码有什么关系?您的流操作为每个元素调用相同的方法,只有布尔参数可能不同。第二部分,if(isAutomaticDataEnabled(name)) return populateDataFields(input,false); return populateDataFields(input,true);return populateDataFields(input, !isAutomaticDataEnabled(name)); 没有区别当isAutomaticDataEnabled(name)false 时,参数将始终为true,废弃counter 逻辑。 【参考方案1】:

你总是执行相同的操作,只是传递给populateDataFields方法的boolean参数值不同。

如果isAutomaticDataEnabled(name) 的计算结果为false,您总是将true 传递给该方法,而您对AtomicInteger 所做的一切实际上已过时。您可以做的最简单的事情是在流操作之前检查此条件并执行直接操作,始终将true 传递给populateDataFields 方法。

在另一种情况下,您仅将true 传递给input.getStatus().equals(DataStatus.COMPLETE) 评估为false 的遇到顺序中的第一项。不依赖于处理顺序的唯一方法是首先识别受影响的元素。由于此元素的标识和结果列表都取决于排序操作的结果,因此排序必须在它之前进行。

public List<Data> toData(List<Idata> dataList, String name) 
    if(isAutomaticDataEnabled(name)) 
        dataList = new ArrayList<>(dataList);
        dataList.sort(null);
        Idata firstNotComplete = dataList.stream()
            .filter(input -> !input.getStatus().equals(DataStatus.COMPLETE))
            .findFirst().orElse(null);
        return dataList.stream().sorted()
            .map(input -> populateDataFields(input, input == firstNotComplete))
            .collect(Collectors.toList());
    
    else return dataList.stream().sorted()
        .map(input -> populateDataFields(input, true))
        .collect(Collectors.toList());

冗余较少的替代方案是

public List<Data> toData(List<Idata> dataList, String name) 
    dataList = new ArrayList<>(dataList);
    dataList.sort(null);
    Predicate<Idata> p = isAutomaticDataEnabled(name)? dataList.stream()
        .filter(input -> !input.getStatus().equals(DataStatus.COMPLETE))
        .findFirst().map(Predicate::<Idata>isEqual).orElse(x -> false): x -> true;
    return dataList.stream()
        .map(input -> populateDataFields(input, p.test(input)))
        .collect(Collectors.toList());

虽然当isAutomaticDataEnabled(name)false 时,第一个变体可能会更有效。

请注意,当DataStatusenum 类型时,您可以简单地写成input.getStatus() != DataStatus.COMPLETE 而不是!input.getStatus().equals(DataStatus.COMPLETE)

【讨论】:

以上是关于从流中删除 AtomicInteger 计数器的主要内容,如果未能解决你的问题,请参考以下文章

从 Tweepy 流中获取转推和最喜欢的计数

从流中读取失败 - MySqlException

连续从流中读取?

从流中播放波形文件

如何使用 Java 8 lambda 从流中获取一系列项目?

WPF中的MediaElement从流中播放视频?