【问题标题】:Fatal Exception: java.lang.IllegalArgumentException: Comparison method violates its general contract致命异常:java.lang.IllegalArgumentException:比较方法违反其一般合同
【发布时间】:2021-08-13 20:59:35
【问题描述】:

我知道有很多类似的问题,并且通过阅读这些问题的答案我得到了很大的帮助,但是我无法看到我的客户是如何面对这个问题的。而且只有一个客户面临这个问题。

我有一个列表,我正在使用 Comparator 界面对该列表进行排序。大家有没有发现以下代码有问题?

    private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
        @Override
        public int compare(BiologySample left, BiologySample right) {
            if (left == right || (left != null && right != null && left.getSampleDateTime() == right.getSampleDateTime())) {
                return 0;
            }

            if (left == null || left.getSampleDateTime() == null) {
                return 1;
            }

            if (right == null || right.getSampleDateTime() == null) {
                return -1;
            }

            return right.getSampleDateTime().compareTo(left.getSampleDateTime());
        }
    }

这就是我调用这个函数的方式

Collections.sort(biologySamples, new BiologySamplesComparator());

我知道这种情况下的主要问题是传递性。但是我不知道是什么违反了该规则。

getSampleDateTime() 如何返回日期Fri Apr 09 17:00:00 PDT 2021


更新 这就是我能够解决问题的方法。 我希望这会有所帮助,我被这个问题困扰了很长时间。

    private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
        @Override
        public int compare(BiologySample left, BiologySample right) {
            if (left == null) {
                if (right == null) {
                    return 0;
                } else {
                    return 1;
                }
            } else if (right == null) {
                return -1;
            } else if (left == right) {
                return 0;
            }
            if (left.getSampleDateTime() == null) {
                if (right.getSampleDateTime() == null) {
                    return 0;
                } else {
                    return 1;
                }
            } else if (right.getSampleDateTime() == null) {
                return -1;
            } else if (left.getSampleDateTime() == right.getSampleDateTime()) {
                return 0;
            }

            return right.getSampleDateTime().compareTo(left.getSampleDateTime());
        }
    }

【问题讨论】:

    标签: java android collections comparator


    【解决方案1】:

    null“样本”与具有空时间戳的非空样本进行比较时,可能会出现不一致。

    Sample a = null;
    Sample b = new Sample(null);
    
    bsc.compare(a, b); // -> 1, a > b
    bsc.compare(b, a); // -> 1, b > a
    

    首先,如果可能的话,您应该将示例类中的Date 替换为Instant,然后这样说让您的生活更简单:

    public static final Comparator<Sample> ORDER_BY_TIMESTAMP =
      Comparator.nullsLast(Comparator.comparing(
          Sample::getDateTime,
          Comparator.nullsLast(Comparator.naturalOrder())
      );
    

    如果可以排除空值,那就更简单了:

    Comparator.comparing(Sample::getDateTime);
    

    【讨论】:

    • 感谢您的建议。我能够通过以与您不同的方式更改我的代码来解决问题。检查我的问题的描述。无论如何,谢谢。
    • @ParteekSinghBedi 与其使用解决方案编辑您的问题,不如将解决方案发布为您自己问题的答案。如果它是有帮助的,你甚至可以接受它(用支票标记它)。如果其他答案也有帮助,您可以投票。
    • 添加解决方案作为答案。
    【解决方案2】:

    我在某些情况下遗漏了一些条件,这就是我能够解决问题的方法。

        private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
            @Override
            public int compare(BiologySample left, BiologySample right) {
                if (left == null) {
                    if (right == null) {
                        return 0;
                    } else {
                        return 1;
                    }
                } else if (right == null) {
                    return -1;
                } else if (left == right) {
                    return 0;
                }
                if (left.getSampleDateTime() == null) {
                    if (right.getSampleDateTime() == null) {
                        return 0;
                    } else {
                        return 1;
                    }
                } else if (right.getSampleDateTime() == null) {
                    return -1;
                } else if (left.getSampleDateTime() == right.getSampleDateTime()) {
                    return 0;
                }
    
                return right.getSampleDateTime().compareTo(left.getSampleDateTime());
            }
        }
    

    感谢Why does my compare methd throw IllegalArgumentException sometimes?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多