获取与 POJO 变量的最大值匹配的所有 POJO 项

Getting all the POJO items that match max value of a POJO variable

我有一个 POJO class,我想从中收集与给定 POJO 变量的最大值相匹配的所有 POJO 对象。

我有下面的 POJO class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class IPTraceData implements Serializable {

    private String factId;
    private long startIp;
    private long endIp;
    private int confidence;
    private LocalDate date;
    private long ipaddr;
}

我想获取所有与 confidence 变量的最大值相匹配的 POJO 对象。

我可以在 Java 8.

中使用以下代码获得结果
int max = allTraces.stream()
            .max(Comparator.comparing(IPTraceData::getConfidence))
            .get()
            .getConfidence();

List<IPTraceData> traceData = allTraces
            .stream()
            .filter(m -> m.getConfidence() == max)
            .collect(Collectors.toList());

但是,我正在尝试使用单个流语句在 Java8 中编写代码。 如何使用单流语句实现相同的目的?

从技术上讲,可以使用 单个语句 来实现该逻辑。但是这个解决方案有一个额外的成本,即在内存中分配一个中间映射 Map<Integer,<List<IPTraceData>>.

先找到max confidence然后再根据它处理数据集的做法比较performance-wise.

List<IPTraceData> traceData = allTraces
            .stream()
            .collect(Collectors.groupingBy(IPTraceData::getConfidence))
            .entrySet().stream()
            .max(Map.Entry.comparingByKey())
            .map(Map.Entry::getValue)
            .orElse(Collections.emptyList());

注:

  • 当代码不包含任何确保可选对象不为空的检查时,避免将 get() 与可选对象一起使用。如果您希望它不为空并且您的意图是使代码无法强调问题,请改用 orElseThrow()。这会让你的意图更加明确。

如果你想在不使用额外的中间内存的情况下完成它,并且完全可并行化,你可以使用通用的 collect 功能。像这样的东西(未经测试;随意提取方法以使其更具可读性):

List<IPTraceData> traceData = allTraces.stream()
    .collect(
        // supplier
        ArrayList::new,

        // accumulator
        (r, t) -> {
          if (r.isEmpty()) {
            r.add(t);
          } else {
            int currentMaxConfidence = r.get(0).getConfidence();
            if (t.getConfidence() == currentMaxConfidence) {
              r.add(t);
            } else if (t.getConfidence() > currentMaxConfidence) {
              r.clear();
              r.add(t);
            }
          }
        },

        // combiner
        (left, right) -> {
          if (left.isEmpty()) {
            left.addAll(right);
          } else if (!right.isEmpty()) {
            int leftMax = left.get(0).getConfidence();
            int rightMax = right.get(0).getConfidence();

            if (leftMax == rightMax) {
              left.addAll(right);
            } else if (leftMax < rightMax) {
              left.clear();
              left.addAll(right);
            }
          }
        }
    );

您也可以使用 reduce() 而不是 collect() 对 non-mutable 数据结构做同样的事情,但是使用普通的 Java 列表有点麻烦non-mutable 方式。

请注意,我知道该代码非常笨拙,可能不值得,但我纯粹是在回答您的问题,对您要如何使用它以及在何处使用它没有任何假设。