迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Java >

修复 Java 中的比较方法违反其一般契约错误

作者:迹忆客 最近更新:2023/07/12 浏览次数:

本篇文章我们将了解 Comparator 和 Comparable 接口使用的比较规则,这将导致Java中比较方法违反其一般契约错误的可能原因。 之后,我们将了解使用 Comparator 和 Comparable 接口的两种解决方案。


Comparator 和 Comparable 接口之间的区别

这是Java核心库中的两个接口。 比较器是一个比较两个不同对象并且独立于其他任何东西的函数。

它只查找两个输入,继续处理它们,并呈现结果。

另一方面,Comparable 是我们与数据类混合的接口。 例如,我们有一个包含一些数据的类; Comparable 接口将用于比较该类的第一个对象与同一类的第二个对象。

这意味着 Comparable 接口表明该实例可以与同一类的另一个实例进行比较。 请记住,Comparable 定义了类的自然顺序。

在其他方面,它与 Comparator 一样也是一个比较函数,并且在返回值、传递、自反等方面具有相同的规则。


Comparator 和 Comparable 的比较规则

比较方法违反了其一般契约,这意味着 Comparator 或 Comparable(基于我们正在使用的)有错误并违反了一致性规则之一。 一致性规则是什么?

下面我们就来学习一下它们。

我们假设我们已经为整数类型值编写了 Java 程序。 因此,我们的比较函数必须遵守以下规则。

  • 给定任意两个整数 a 和 b,必须满足三分法,这意味着以下关系之一必须为真:
    • a 小于 b(如果 a < b,则返回 -ve 值)
    • a 等于 b (如果 a == b 则返回 0)
    • a 大于 b(如果 a > b,则返回 +ve 值)
  • 它必须满足传递性,这意味着如果 a < bb < c,那么对于任何三个数字 a、b、c,都意味着 a < c
  • 第三条规则是关于反对称的,其中 a < b 意味着 ~b < a
  • 可替代性也是一种比较规则,假设 a == ba < c; 这意味着 b < c
  • 最终的比较规则是自反性,其中 a == a; 也 ~a < a

如果违反任何这些规则,我们会收到错误消息,指出比较方法违反了其一般契约。 让我们借助下面的代码示例来学习它。


Java代码具有比较方法违反了其一般契约错误

示例代码:

//import libraries
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import static java.util.stream.Collectors.toCollection;

//Main
public class Main {
    public static void main(String[] args) {
        //generate random numbers
        List<Integer> list = new Random(209).ints(32L)
                             .boxed()
                             .collect(toCollection(ArrayList::new));
        //sort using lambda expression
        list.sort(logging((a,b) -> a-b));
   }//end main()

    //logging the comparisons
    static Comparator<Integer> logging(Comparator<Integer> c) {
       return (a, b) -> {
           int r = c.compare(a, b);
           System.err.printf("%,14d %,14d => %,14d\n", a, b, r);
           return r;
       };
    }//end logging()
}//end class

在此代码中,我们使用 Random 类的 ints 实例生成一些随机数,该实例用于生成随机数流。

对于这段代码,如果我们排序为 list.sort((a, b) -> a - b); 那么,我们将无法确定问题是什么以及问题发生在哪里。 这就是为什么我们通过日志记录对其进行排序,这将有助于我们识别它。

它给了我们一个错误,但它也提供了很多数字的比较。 我们不会讨论全部,但其中的几个就足以发现错误。

输出:

修复java中比较方法违反其一般契约错误 - 错误

我们可以看到,程序在这里违反了一致性规则,导致了这个错误。 在下一节中,我们将使用 Comparator 和 Comparable 来解决这个问题。


使用 Comparator 和 Comparable 接口的 Java 解决方案

让我们使用随机数较少的 Comparator 接口。

示例代码:

//import libraries
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import static java.util.stream.Collectors.toCollection;

//Main
public class Main {
    public static void main(String[] args) {
        //generate random numbers
        List<Integer> list = new Random(5).ints(32L)
                             .boxed()
                             .collect(toCollection(ArrayList::new));
        //sort using lambda expression
        list.sort(logging((a,b) -> a-b));
   }//end main()

    //logging the comparisons
    static Comparator<Integer> logging(Comparator<Integer> c) {
       return (a, b) -> {
           int r = c.compare(a, b);
           System.err.printf("%,14d %,14d => %,14d\n", a, b, r);
           return r;
       };
    }//end logging()
}//end class

这段代码执行成功。 我们不会进行所有的比较,但我们会看到其中的一些进行确认。

检查以下屏幕截图。

输出:

修复java中比较方法违反其一般契约错误 - 解决方案1

让我们了解一下使用 Comparable 接口进行比较的无错误 Java 代码。 要使用这个接口,我们必须创建一个包含数据的类。

下面我们就来做一下吧。

示例代码(Students.java 类):

public class Student implements Comparable<Student> {
    private String firstName;
    private String lastName;

    public Student(String firstName, String lastName){
        this.firstName = firstName;
        this.lastName = lastName;

    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int compareTo(Student other) {
        /*
        compare the last names and save the result
        in `compareResult` variable
        */
        int compareResult = this.lastName.compareTo(other.lastName);

        /*
        If both last names match, then it would be true means 0. So,
        dive into the `if` condition and check if the count of their
        first name matches.
        if this.count == other.count return 0
        if this.count > other.count return 1
        if this.count < other.count return -1
        */

        if(compareResult == 0){
            if(this.firstName.chars().count() ==  other.firstName.chars().count()) {
                compareResult = 0;
                return compareResult;
            }
            else if(this.firstName.chars().count() > other.firstName.chars().count()){
               compareResult = 1;
                return compareResult;
            }
            else{
                compareResult =  -1;
                 return compareResult;
            }
        }
        else{
            return compareResult;
        }
    }
}

示例代码(Main.java 类):

public class Main {

    public static void main(String[] args) {
        Student std1 = new Student ("Mehvish", "Ashiq");
        Student std2 = new Student ("Mehvish", "Ashiq");
        System.out.println("Result of Comparison 1: " + std1.compareTo(std2));

        Student std3 = new Student ("Aftab", "Ashiq");
        Student std4 = new Student ("Mehvish", "Ashiq");
        System.out.println("Result of Comparison 2: " + std3.compareTo(std4));

        Student std5 = new Student ("Mehr-un-nissa", "Ashiq");
        Student std6 = new Student ("Mehvish", "Ashiq");
        System.out.println("Result of Comparison 3: " + std5.compareTo(std6));
   }
}

输出:

Result of Comparison 1: 0
Result of Comparison 2: -1
Result of Comparison 3: 1

在此代码中,如果两个对象的姓氏相同,我们将比较名字的字母数。

正如我们所看到的,结果是一致的。 如果 a==ba<ba>b,则分别返回 0、-1 和 1。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

修复 Java 中错误 Error: Else Without if

发布时间:2023/07/13 浏览次数:183 分类:Java

本篇文章我们将了解在用 Java 编写代码时只说 'else' without 'if' 的错误。 我们还将找出导致此错误的可能原因并找到解决方案。Java 中 error: 'else' without 'if'

Java 中的无效字符常量

发布时间:2023/07/13 浏览次数:152 分类:Java

本 Java 文章将讨论无效字符常量。 但在此之前,我们需要了解字符常量。Java字符常量 单字符常量,也称为字符常量,是封装在一对 '' 或单引号中的单个字符。

解决 Java 中 Missing Method Body or Declare Abstract

发布时间:2023/07/13 浏览次数:68 分类:Java

本篇文章讨论编译时错误、missing method body, or declare abstract。 在这里,我们将经历三个不同的步骤。首先,我们将了解一个Java程序来了解错误。 其次,突出显示此错误的可能原因,并最终找到

在 Java 中使用 Scanner 时没有此类元素异常

发布时间:2023/07/13 浏览次数:72 分类:Java

本篇文章将介绍如何在 Java 中使用 Scanner 时解决 NoSuchElementException 错误。在 Java 中使用 Scanner 时没有此类元素异常 Scanner 类用于在 Java 程序中获取用户输入。 它使用多种实用方法,如 next()、

Java 错误 Java.Net.SocketTimeoutException: Connection Timed Out

发布时间:2023/07/13 浏览次数:161 分类:Java

在本篇文章中,我们将讨论 java.net.SocketTimeoutException: Connection timed out。 但首先,让我们仔细看看套接字和超时的概念。Java 中的套接字 两个计算机应用程序之间的逻辑链接可能有多个端点,其

Java 错误 Char Cannot Be Dereferenced

发布时间:2023/07/13 浏览次数:87 分类:Java

本篇文章介绍如何解决Java的 java char cannot be dereferenced 错误。Java Char cannot be dereferenced 当我们尝试使用 equals() 方法检查一个字符是否与另一个字符相等时,会出现错误 java char can not be dereferenc

JavaFX 中 InvocationTargetException

发布时间:2023/07/13 浏览次数:165 分类:Java

本篇文章介绍如何解决 JavaFX 中的 InvocableTargetException。修复 JavaFX 中的 InspirationTargetException 当我们使用 JavaFX 时,会发生 InvokingTargetException 异常。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便