compare用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了compare用法相关的知识,希望对你有一定的参考价值。

Compare with your sweater,I like mine better。这句话对吗。如果对,这里compare什么用法?

对的。这里表示“把……与……相比”时,compare…with与compare…to…皆可用。

1.vt. 比较;对照。如:

Compare your answers with those at the back of the book to see if they are right.

把你的答案同书后面的答案对照一下,看看是否正确。

My handwriting can not be compared with my father’s.

我的书法不能与我父亲的相比。

If you compare the two books, you will see that this one is better.

如果你比较一下这两本书,你会发现这一本好一些。

2.vt. 喻为;比拟。如:

Man’s life is often compared do a candle.人生常被比为蜡烛。

Shakespeare compared the world to a stage.莎士比亚把人世比做舞台。

3.comparison n. 比较;对照。如:

He looks older by comparison.比较起来,他显得老些。

It is beyond(=out of)all comparison.这是无可比拟的。

A critical comparison of Carlyle and Emerson就卡莱尔与爱默生(两人的信条或文学风格)而进行的比较与研究

4.词组

a fair comparison公正的比较

a rough comparison粗略的比较

a minute comparison详细比较

tabular comparison比较表

in comparison with that man与那人相比

the basis of comparison比较的基础

the countries under comparison相比的各国

without(=beyond)comparison无与伦比

comparison between nature and art自然与艺术之间的比较

comparison of hands笔迹的比较

the comparison of one thing to another一样东西比做另一样。如:

The comparison of heart to a pump is a very common one.

把心脏比成水泵是很常见的比喻。

bear(=stand;sustain)a comparison with比得上,不差于

challenge comparison with one’s predecessors向前任挑战

draw a comparison between then把它们加以比较

in/by comparison with与……比较

A train is slow in comparison with a plane.同飞机比较,火车走得慢。

特别提醒

compare…with…表示“把……与……相比(同类相比)”,

compare…to…表示“把……比做……(异类相比,比喻)”。

在表示“把……与……相比”时,compare…with与compare…to…皆可用,尤其是用在过去分词作状语的句子中。
参考技术A 1、(1)compare A with B:A与B作比较
Eg:Researchers compared living conditions in London with those in other cities.
研究人员把伦敦的生活条件与其他城市的做了比较。

(2)比较两者相似之处
Eg:She has often been compared to her mother.
人们常说她像她的母亲。

2、compare sth. on sth.:对于……作比较;含有互相交流的意思
Eg:We've been comparing notes on our trips to India.
我们一直在谈论我们印度之行的见闻感想。

3、compare……to 与……相比(用以比较不同事物)
Eg:Their prices are low compared to those in other shops.

4、cannot compare with\does not compare with
不如……好
Eg:Living in a town can't compare with living in the contry.
乡村生活比城镇的生活好得多。

另外,建议海豚,如果你还是一个学生的话,最好去买一个快译通或者诺亚舟这类的,对于英语的学习很有帮助:)
参考技术B compare…with…表示“把……与……相比(同类相比)”,
compare…to…表示“把……比做……(异类相比,比喻)”。
在表示“把……与……相比”时,compare…with与compare…to…皆可用,尤其是用在过去分词作状语的句子中。
非谓语动词做状语时,用主动还是被动取决于句子的主语,如:
Comparedwithhisroom,myroomisevensmaller.句子的主语是myroom,所以用被动。我的房子被比较。
Comparinghisroom,Ifindmyroomisevensmalle.主语是I所以用主动。我进行比较这个动作。注意没有with.
主干句主语you和compare是被动关系,即:youarecomparedwithyourclassmates.所以用comparedwith。
如果主干句主语you和compare是主动关系,就可以用comparing.
compared表示被动含义
comparing表示主动含义
comparedwith和comparingwith在用法上相同,基本没有区别,这类用法不用考虑词组与后面的主语是主动关系还是被动关系,两者可替换使用,这类用法还有suposing和suposed

Comparator与Comparable用法与区别

一、概述。

??Comparator和Comparable两者都属于集合框架的一部分,都是用来在对象之间进行比较的,但两者又有些许的不同,我们先通过一个例子来看一下他们的区别,然后再分别学习下它们的源码。

先来看一下Comparable的例子,定义实体类Student,实现Comparable,重写compareTo方法:

public class Student implements Comparable<Student> {
    private String name;
    private Integer age;
    private Integer score;

    public Student(String name, Integer age, Integer score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    @Override
    public int compareTo(Student o) {
        return this.getName().compareTo(o.getName());
    }
}

进行测试:

public static void main(String[] args) {
    Student student1 = new Student("zhangsan", 1, 80);
    Student student2 = new Student("lisi", 3, 90);
    Student student3 = new Student("wangwu", 2, 100);
    List<Student> list = new ArrayList<>();
    list.add(student1);
    list.add(student2);
    list.add(student3);
    Collections.sort(list);
    list.stream().forEach(n -> System.out.println(n.toString()));
}

output:

Student{name=‘lisi‘, age=3, score=90}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘zhangsan‘, age=1, score=80}

从上面的例子我们大致了解了Comparable接口的使用,也就是说同一个类的对象之间如果要进行比较,需要实现Comparable接口,并且实现compareTo方法。这样比较的时候就会按照这个规则来进行比较。

再来看一下Comparator的例子,定义实体类Student,

public class Student {
    private String name;
    private Integer age;
    private Integer score;

    public Student(String name, Integer age, Integer score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
}

自定义比较器:

class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getAge() > o2.getAge()) {
            return 1;
        } else if (o1.getAge() < o2.getAge()) {
            return -1;
        } else {
            return 0;
        }
    }
}

class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

进行测试:

public static void main(String[] args) {
    Student student1 = new Student("zhangsan", 1, 80);
    Student student2 = new Student("lisi", 3, 90);
    Student student3 = new Student("wangwu", 2, 100);
    List<Student> list = new ArrayList<>();
    list.add(student1);
    list.add(student2);
    list.add(student3);
    // 这时候如果直接  Collections.sort(list) 会由于Student没有默认的自然排序,编译不过。
    Collections.sort(list, new AgeComparator());
    list.stream().forEach(n -> System.out.println(n.toString()));
    System.out.println("
-------------------");
    Collections.sort(list, new NameComparator());
    list.stream().forEach(n -> System.out.println(n.toString()));
}

先按照AgeComparator比较规则进行比较,再按照NameComparator比较器进行比较,output:

Student{name=‘zhangsan‘, age=1, score=80}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘lisi‘, age=3, score=90}

-------------------
Student{name=‘lisi‘, age=3, score=90}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘zhangsan‘, age=1, score=80}

??可以看到,我们如果要对实体类的对象进行比较,在不修改原实体类的情况下,可以通过实现多个Comparator来实现多个比较规则。通过Comparator,我们可以自定义比较规则,针对对象的属性或者字段等来进行比较,而Comparable就实现不了,因为它的compareTo方法只能有一种比较规则。
??实现Comparator,同样也要实现它的一个方法compare。由于一般情况下我们实现的Comparator只有一个compare方法,所以我们可以对实现类进行一些优化:

  1. 使用匿名类来代替单独的实现类。比如我们可以将 Collections.sort(list, new NameComparator());替换为:
Collections.sort(list, new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getName().compareTo(o2.getName());
    }
});
  1. 借助JDK1.8的lambda表达式,进一步优化为:
Collections.sort(list, (o1, o2) -> o1.getName().compareTo(o2.getName()));
  1. 借助JDK1.8中Comparator接口中的新的方法comparing,再次优化:
Collections.sort(list, Comparator.comparing(Student::getName));

区别

了解了他们的简单使用之后,我们可以来简单分析一下他们的区别了。
相同点:

  1. 两者都是用来用作对象之间的比较,都可以自定义比较规则;
  2. 两者都是返回一个描述对象之间关系的int;

不同点:

  1. 实现了Comparable的意思是我可以把自己和另一个对象进行比较;而实现了Comparator的意思是我可以比较其他两个对象;也就是说Comparable是一个可比较的对象可以将自己与另一个对象进行比较;而Comparator是比较两个不同的对象。
  2. 使用Comparable需要修改原先的实体类,是属于一种自然排序。而Comparator则不用修改原先类。
  3. 即使修改了Comparable实体类,Comparable也仅有一种比较规则。而Comparator可以实现多个,来提供多个比较规则。

下面来看一下各自的源码,由于都是接口,我们主要看下JDK1.8之后的默认实现方法。

Comparable

Comparable就比较简单了,只有一个compareTo方法。我们实现该方法的时候注意一下对象的NPE(NullPointerException)问题就可以了。

Comparator

Comparator除了默认的compare和equals接口之外,其他的基本都是默认实现方法。我们来看一下这些方法的实现。

reversed方法

返回逆序比较的比较器,这个就很简单,底层直接使用Collections的reverseOrder来实现。

default Comparator<T> reversed() {
    return Collections.reverseOrder(this);
}
thenComparing

这个方法是多条件排序的方法,当我们排序的条件不止一个的时候可以使用该方法。比如说我们对Student先按照age字段排序,再按照score排序,就可以使用thenComparing方法:

Student student1 = new Student("zhangsan", 1, 80);
Student student2 = new Student("lisi", 3, 90);
Student student3 = new Student("wangwu", 2, 100);
Student student4 = new Student("tom", 3, 75);
List<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
list.add(student3);
list.add(student4);
Collections.sort(list, Comparator.comparing(Student::getAge).thenComparing(Student::getScore));
list.stream().forEach(n -> System.out.println(n.toString()));

output:

Student{name=‘zhangsan‘, age=1, score=80}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘tom‘, age=3, score=75}
Student{name=‘lisi‘, age=3, score=90}

如果有需要,我们可以借助这个方法构造更复杂的排序方式。该方法有多个重载的方法,并且有几个支持各种类型的方法如:

default <U> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor,
    Comparator<? super U> keyComparator)
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
    return thenComparing(comparingInt(keyExtractor));
}

不过,底层调用的全是同样的方法:

default Comparator<T> thenComparing(Comparator<? super T> other) {
    Objects.requireNonNull(other);
    return (Comparator<T> & Serializable) (c1, c2) -> {
        int res = compare(c1, c2);
        return (res != 0) ? res : other.compare(c1, c2);
    };
}
reverseOrder和naturalOrder

naturalOrder是返回自然排序的比较器,reverseOrder恰好和naturalOrder相反,两者都是用于返回实现了Comparable接口的对象的比较器。我们借助刚才Comparator和Comparable两者进行比较时的Comparable的代码,来测试一下,先看一下自然顺序,结果和原来一样:

Collections.sort(list, Comparator.naturalOrder());

output:

Student{name=‘lisi‘, age=3, score=90}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘zhangsan‘, age=1, score=80}

再看一下逆序:

Collections.sort(list, Comparator.reverseOrder());

output:

Student{name=‘zhangsan‘, age=1, score=80}
Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘lisi‘, age=3, score=90}

这两个方法说白了就是将Comparable的方式转换为Comparator,因为Comparable的功能有限,不方便我们基于Comparable进行扩展。底层实现分别借助于工具类Collections及Comparators来实现。Comparators是专门用于支持Comparator的内部类。

public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
    return Collections.reverseOrder();
}

public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
    return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
}
nullsFirst和nullsLast方法

这两个方法有点意思,是说如果排序的字段为null的情况下这条记录怎么排序。nullsFirst是说将这条记录排在最前面,而nullsLast是说将这条记录排序在最后面。举个例子就可以了:

public static void main(String[] args) {
    Student student1 = new Student("zhangsan", 1, 80);
    Student student2 = new Student("lisi", null, 90);
    Student student3 = new Student("wangwu", 2, 100);
    List<Student> list = new ArrayList<>();
    list.add(student1);
    list.add(student2);
    list.add(student3);
    Comparator<Student> comparator = Comparator.comparing(Student::getAge, 
            Comparator.nullsLast(Comparator.reverseOrder()));
    Collections.sort(list, comparator);
    list.stream().forEach(n -> System.out.println(n.toString()));
}

按照age进行逆序排列,将key为null的排到最后面,output:

Student{name=‘wangwu‘, age=2, score=100}
Student{name=‘zhangsan‘, age=1, score=80}
Student{name=‘lisi‘, age=null, score=90}

按照age进行自然顺序排列,将key为null的排再最前面:

Comparator<Student> comparator = Comparator.comparing(Student::getAge,
            Comparator.nullsFirst(Comparator.naturalOrder()));
Collections.sort(list, comparator);

output:

Student{name=‘lisi‘, age=null, score=90}
Student{name=‘zhangsan‘, age=1, score=80}
Student{name=‘wangwu‘, age=2, score=100}

如果多个key都为null的话,那将无法保证这几个对象的排序。
源码很简单,直接通过Comparators内部类实现的。

public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(true, comparator);
}

public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(false, comparator);
}
comparing方法

comparing方法我们已经用过,就是获取对象的比较器也就是比较规则,有几个重载方法及对应类型的方法,第一个参数接受的是函数式表达式。我们使用例子来看下:

因为前些时候用到了布尔类型的排序,所以我们这次就拿Boolean类型的排序来进行测试。修改原先Student类,添加一个布尔类型字段likeGame,然后测试下:

public static void main(String[] args) {
    List<Student> list = Arrays.asList(
            new Student("zhangsan", 1, 80, true),
            new Student("wangwu", 3, 100, false),
            new Student("zisi", 4, 110, true),
            new Student("zisi", 2, 110, true)
    );
    Collections.sort(list, Comparator.comparing(Student::getLikeGame).thenComparing(Student::getAge));
    list.stream().forEach(n -> System.out.println(n.toString()));
}

output:

Student{name=‘wangwu‘, age=3, score=100, likeGame=false}
Student{name=‘zhangsan‘, age=1, score=80, likeGame=true}
Student{name=‘zisi‘, age=2, score=110, likeGame=true}
Student{name=‘zisi‘, age=4, score=110, likeGame=true}

这就实现了按照Student对象的likeGame进行自然排序,同样,两个参数的接口,第二个参数可以指定具体的比较规则:

Collections.sort(list, Comparator.comparing(Student::getLikeGame, Comparator.reverseOrder())
    .thenComparing(Student::getAge));
list.stream().forEach(n -> System.out.println(n.toString()));

这就实现了按照逆序对likeGame进行排序,output:

Student{name=‘zhangsan‘, age=1, score=80, likeGame=true}
Student{name=‘zisi‘, age=2, score=110, likeGame=true}
Student{name=‘zisi‘, age=4, score=110, likeGame=true}
Student{name=‘wangwu‘, age=3, score=100, likeGame=false}

简单说下,Boolean类型的排序默认规则是false排在前面,而true排在后面,原因我们可以看下Boolean的compare方法。

public int compareTo(Boolean b) {
    return compare(this.value, b.value);
}

public static int compare(boolean x, boolean y) {
    return (x == y) ? 0 : (x ? 1 : -1);
}

comparing接口的源码可以简单看下,其中一个源码如下:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor) {
    
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

总结

??Comparator和Comparable这两个接口,一般只要我们涉及到集合的排序,都少不了要与这两个接口打交道,而平时我们使用Comparator很显然会更多一些,所以本篇文章主要学习了下两者的使用,区别,并看了看源码,学习了JDK8之后Comparator增加的一些方法。

其实Comparator的方法不太多,总结一下就几种:

  1. comparing获取比较器,thenComparing多条件比较器;
  2. reverseOrder与naturalOrder用于Comparable向Comparator的转换;
  3. nullsFirst和nullsLast用于处理排序字段为null的情况;
  4. 剩余的就是原先的compare和equals方法。

另外使用这两个接口的过程中,需要注意的点就是对null的检测,处理。

##################################################################################

链接:https://www.jianshu.com/p/50b561044c60






以上是关于compare用法的主要内容,如果未能解决你的问题,请参考以下文章

Comparable接口和Comparator接口的不同用法

JAVA Comparator 接口排序用法

跟王老师学集合java中Comparator的用法

Java 里的Comparator接口里的compare方法怎么确定升降序的?

BigDecimal对比大小使用compare而不使用equals

Stream流的排序用法