Java8新特性(4).java比较和排序接口之比较器Comparator和比较接口Comparable

在JAVA中实现对象的排序可以使用Comparable接口,也可以使用Comparator接口.

  • Comparable : 需要自己实现比较的方法compareTo,是一个内部排序器
  • Comparator : 可以使用其默认的方法和lambda表达式来实现排序,是一个外部排序器,更像一个工具接口

一、Comparable接口

  • 表明实现的对象是一个可排序的类
1.一个需要排序的类,需要实现Comparable接口中的compareTo方法
  1. class ArticleInfo implements Comparable<ArticleInfo> {
  2. private Integer articleId;
  3. private String title;
  4. private Integer views;
  5. private Integer comments;
  6. private Long createTime;
  7. public ArticleInfo(Integer articleId, String title, Integer views, Integer comments, Long createTime) {
  8. this.articleId = articleId;
  9. this.title = title;
  10. this.views = views;
  11. this.comments = comments;
  12. this.createTime = createTime;
  13. }
  14. public Integer getArticleId() {
  15. return articleId;
  16. }
  17. public void setArticleId(Integer articleId) {
  18. this.articleId = articleId;
  19. }
  20. public String getTitle() {
  21. return title;
  22. }
  23. public void setTitle(String title) {
  24. this.title = title;
  25. }
  26. public Integer getViews() {
  27. return views;
  28. }
  29. public void setViews(Integer views) {
  30. this.views = views;
  31. }
  32. public Integer getComments() {
  33. return comments;
  34. }
  35. public void setComments(Integer comments) {
  36. this.comments = comments;
  37. }
  38. public Long getCreateTime() {
  39. return createTime;
  40. }
  41. public void setCreateTime(Long createTime) {
  42. this.createTime = createTime;
  43. }
  44. @Override
  45. public int compareTo(ArticleInfo info) {
  46. if (this.views > info.getViews()) {
  47. return -1;
  48. } else if (this.views.equals(info.getViews())) {
  49. return 0;
  50. } else {
  51. return 1;
  52. }
  53. }
  54. @Override
  55. public String toString() {
  56. return "ArticleInfo{" +
  57. "articleId=" + articleId +
  58. ", title='" + title + '\'' +
  59. ", views=" + views +
  60. ", comments=" + comments +
  61. ", createTime=" + createTime +
  62. '}';
  63. }
  64. }

注:在实现compareTo方法时,一定要判断当两个对象的值相等的情况,不然,可能在集合对象比较时出错

2.调用排序方法

针对集合对象,可以使用

  • 工具类Collections.sort方法
  • 使用集合对象的sort方法

无论是Collections.sort方法还是集合对象的sort方法都可以传入一个排序方式的参数

  • Comparator.naturalOrder() : 正序
  • Comparator.reverseOrder() : 倒序

注:正序和倒序是相对于实现的Comparable接口的compareTo接口而言的,实现的就是正序,reverseOrder就是针对实现的CompareTo的结果再进行倒序

  1. List<ArticleInfo> articleInfoList = new ArrayList<ArticleInfo>(10);
  2. Long now = System.currentTimeMillis();
  3. articleInfoList.add(new ArticleInfo(1001, "第一篇文章", 10, 2, now));
  4. articleInfoList.add(new ArticleInfo(1002, "第二篇文章", 29, 3, now+1000));
  5. articleInfoList.add(new ArticleInfo(1003, "第三篇文章", 9, 1, now+5000));
  6. /**
  7. * 1.通过Collections工具类来排序
  8. */
  9. Collections.sort(articleInfoList);
  10. System.out.println(articleInfoList);
  11. Collections.sort(articleInfoList, Comparator.reverseOrder());
  12. System.out.println(articleInfoList);
  13. /**
  14. * 2.通过List等对象的sort方法
  15. */
  16. articleInfoList.sort(Comparator.reverseOrder());
  17. System.out.println(articleInfoList);

二、Comparator接口

1.实现compare抽象方法
  • 定义普通的实体类Article
  1. class Article {
  2. private Integer articleId;
  3. private String title;
  4. private Integer views;
  5. private Integer comments;
  6. private Long createTime;
  7. public Article(Integer articleId, String title, Integer views, Integer comments, Long createTime) {
  8. this.articleId = articleId;
  9. this.title = title;
  10. this.views = views;
  11. this.comments = comments;
  12. this.createTime = createTime;
  13. }
  14. public Integer getArticleId() {
  15. return articleId;
  16. }
  17. public void setArticleId(Integer articleId) {
  18. this.articleId = articleId;
  19. }
  20. public String getTitle() {
  21. return title;
  22. }
  23. public void setTitle(String title) {
  24. this.title = title;
  25. }
  26. public Integer getViews() {
  27. return views;
  28. }
  29. public void setViews(Integer views) {
  30. this.views = views;
  31. }
  32. public Integer getComments() {
  33. return comments;
  34. }
  35. public void setComments(Integer comments) {
  36. this.comments = comments;
  37. }
  38. public Long getCreateTime() {
  39. return createTime;
  40. }
  41. public void setCreateTime(Long createTime) {
  42. this.createTime = createTime;
  43. }
  44. @Override
  45. public String toString() {
  46. return "Article{" +
  47. "articleId=" + articleId +
  48. ", title='" + title + '\'' +
  49. ", views=" + views +
  50. ", comments=" + comments +
  51. ", createTime=" + createTime +
  52. '}';
  53. }
  54. }
  • 实现compare方法
  1. class ArticleComparator implements Comparator<Article> {
  2. @Override
  3. public int compare(Article a1, Article a2) {
  4. return a1.getViews().compareTo(a2.getViews());
  5. }
  6. }
  • 通过实现的比较器进行排序
  1. List<Article> articleList = new ArrayList<Article>(10);
  2. Long current = System.currentTimeMillis();
  3. articleList.add(new Article(1001, "第一篇文章", 10, 2, current));
  4. articleList.add(new Article(1002, "第二篇文章", 29, 3, current+1000));
  5. articleList.add(new Article(1003, "第三篇文章", 9, 1, current+5000));
  6. articleList.sort(new ArticleComparator());
  7. System.out.println(articleList);
2.静态方法
  • naturalOrder : 正序排列(一般使用于自定义的Comparator接口或Comparable接口)
  • reverseOrder : 倒序排列(一般使用于自定义的Comparator接口或Comparable接口)
  • comparing : 比较(传入一个排序函数)
  • comparingInt : 比较int值
  • comparingLong : 比较long型值
  • comparingDouble : 比较double型值
  1. /**
  2. * 按views排序
  3. */
  4. articleList.sort(Comparator.comparing(Article::getViews));
  5. System.out.println(articleList);
  6. /**
  7. * 按comments排序
  8. */
  9. articleList.sort(Comparator.comparing(Article::getComments));
  10. System.out.println(articleList);
  11. articleList.sort(Comparator.comparingInt(Article::getComments));
3.默认方法
  • reversed : 倒序(将之前的对象进行逆向排列)
  • thenComparing : 多重比较
  1. List<Article> articleList = new ArrayList<Article>(10);
  2. Long current = System.currentTimeMillis();
  3. articleList.add(new Article(1001, "第一篇文章", 10, 5, current));
  4. articleList.add(new Article(1002, "第二篇文章", 29, 3, current+1000));
  5. articleList.add(new Article(1003, "第三篇文章", 9, 1, current+5000));
  6. articleList.add(new Article(1004, "第四篇文章", 9, 2, current+5000));
  7. /**
  8. * 按views倒序排列
  9. */
  10. articleList.sort(Comparator.comparing(Article::getViews).reversed());
  11. System.out.println(articleList);
  12. /**
  13. * 先按views倒序,再按comments倒序
  14. */
  15. articleList.sort(Comparator.comparingInt(Article::getViews).reversed().
  16. thenComparing(Comparator.comparingInt(Article::getComments).reversed()));
  17. System.out.println(articleList);
  18. //[Article{articleId=1002, title='第二篇文章', views=29, comments=3, createTime=1548830876084}, Article{articleId=1001, title='第一篇文章', views=10, comments=5, createTime=1548830875084}, Article{articleId=1004, title='第四篇文章', views=9, comments=2, createTime=1548830880084}, Article{articleId=1003, title='第三篇文章', views=9, comments=1, createTime=1548830880084}]
  • 通过thenComparing进行多重条件排序时,只要当前一个条件相同的情况下,才会按下一个指标进行排序(比较适合多个维度先优先级排序的场景)