Java 8+ 流:检查对象实例的两个字段的列表顺序是否正确

标题可能有点模糊,但这是我所拥有的(在私有化代码中):

包含一些字段(包括大十进制数和日期)的类:

class MyObj{
  private java.math.BigDecimal percentage;
  private java.util.Date date;
  // Some more irrelevant fields

  // Getters and Setters
}

在另一个类中,我有这些对象的列表(即)。我现在想要的是一个Java 8流来检查列表是否按验证器的日期和百分比的正确顺序排列。java.util.List<MyObj> myList

例如,以下列表是真实的:

[ MyObj { percentage = 25, date = 01-01-2018 },
  MyObj { percentage = 50, date = 01-02-2018 },
  MyObj { percentage = 100, date = 15-04-2019 } ]

但是这个列表是错误的,因为百分比的顺序不正确:

[ MyObj { percentage = 25, date = 01-01-2018 },
  MyObj { percentage = 20, date = 01-02-2018 },
  MyObj { percentage = 100, date = 15-04-2019 } ]

这个列表也是假的,因为日期的顺序不正确:

[ MyObj { percentage = 25, date = 10-03-2018 },
  MyObj { percentage = 50, date = 01-02-2018 },
  MyObj { percentage = 100, date = 15-04-2019 } ]

一种可能的解决方案可能是像这样创建,然后使用并检查每个单独的 。但是如果可能的话,我真的不想为此目的创建一个类。Pairs!.anyMatchPair<MyObj>Pair

有没有一种方法可以使用或某些东西来循环成对来检查它们?使用Java 8流检查列表中的所有日期和百分比是否按正确的顺序排列的最佳方法是什么?.reduceMyObjMyObj

另一种可能性是按日期对列表进行排序,然后检查它们是否都按百分比顺序排列,如果这比检查两个字段是否相同更容易。但是,比较百分比对的相同问题仍然存在。MyObj

(PS:我将使用它作为一个,我更喜欢Java 8 lambda,因为我也为其他验证器使用了一些,所以它更符合代码的其余部分。然而,在我的问题中,Java 8 lambda更像是一种偏好而不是要求。com.vaadin.server.SerializablePredicate<MyObj> validator


答案 1

好吧,如果你想要一个短路操作,我不认为使用stream-api的简单解决方案存在......我提出一个更简单的方法,首先定义一个方法,该方法将基于某些参数以短路方式告诉您列表是否排序:

 private static <T, R extends Comparable<? super R>> boolean isSorted(List<T> list, Function<T, R> f) {
    Comparator<T> comp = Comparator.comparing(f);
    for (int i = 0; i < list.size() - 1; ++i) {
        T left = list.get(i);
        T right = list.get(i + 1);
        if (comp.compare(left, right) >= 0) {
            return false;
        }
    }

    return true;
}

并通过以下方式调用它:

 System.out.println(
          isSorted(myList, MyObj::getPercentage) && 
          isSorted(myList, MyObj::getDate));

答案 2

我想你几乎在那里尝试使用.您可以像这样完成它:Stream.anyMatch

private static boolean isNotOrdered(List<MyObj> myList) {
    return IntStream.range(1, myList.size()).anyMatch(i -> isNotOrdered(myList.get(i - 1), myList.get(i)));

}

private static boolean isNotOrdered(MyObj before, MyObj after) {
    return before.getPercentage().compareTo(after.getPercentage()) > 0 ||
            before.getDate().compareTo(after.getDate()) > 0;
}

我们可以使用索引来循环访问列表的元素。通过这种方式,我们可以引用列表中的任何元素,例如,上一个元素来比较它。IntStream.range

编辑添加更通用的版本:

private static boolean isNotOrderedAccordingTo(List<MyObj> myList, BiPredicate<MyObj, MyObj> predicate) {
    return IntStream.range(1, myList.size()).anyMatch(i-> predicate.test(myList.get(i - 1), myList.get(i)));
}

这可以像使用上面的谓词那样调用:

isNotOrderedAccordingTo(myList1, (before, after) -> isNotOrdered(before, after));

或者在类中使用方法引用:ListNotOrdered

isNotOrderedAccordingTo(myList1, ListNotOrdered::isNotOrdered)

推荐