使用排序随机播放流 - IllegalArgumentException

Shuffle Stream using sort - IllegalArgumentException

我有这个命令:

list.stream()
    .filter(e -> ...)
    .sorted(comparatorShuffle())
    .findAny()
    .orElse(null);

这是comparatorShuffle():

public static <E> Comparator<E> comparatorShuffle(){

    return new Comparator<>(){
        private final List<Integer> temp = List.of(-1, 1);
        private final Random random = new Random();
        @Override
        @SuppressWarnings("ComparatorMethodParameterNotUsed")
        public int compare(E o1, E o2){
            return temp.get(random.nextInt(temp.size()));
        }
    };

}

有时我会遇到异常:IllegalArgumentException: Comparison method violates its general contract!

我明白为什么我得到这个,这是因为排序(它是随机的)不遵守规则:if A > B && B > C then A > C

有办法解决suppress/ignore这个错误吗?或者另一种不使用 collect?

随机播放流的方法

There is a way to suppress/ignore this error?

没有

你并不是真的在洗牌,你表面上只是试图从流中挑选一个随机元素。

为此,您可以将元素与随机数配对并选择 min/max:

...
.map(a -> new AbstractMap.SimpleEntry<>(Math.random(), a))
.min(Map.Entry.comparingByKey())
.map(Map.Entry::getValue)
.orElse(null)

或者,您可以编写一个自定义收集器,在合并时在两个事物之间随机选择:

.collect(
    Collector.of(
        // Use Optional.empty() as the identity element, if the stream is empty.
        Optional::empty,
        // Optionalize the element, taking it randomly or if we have the identity element.
        (a, b) -> a.isEmpty() || Math.random() > 0.5 ? Optional.of(b) : a,
        // Merge.
        (a, b) -> Math.random() > 0.5 ? b : a,
        // Unwrap the value.
        r -> r.orElse(null)))

这个替代方案的一个大问题是它没有从流中统一选择(你从流中获得任何一个元素的可能性都不相同),而你使用的是第一种方式。