首页 > 解决方案 > Java 8 使用比较器和选项进行排序

问题描述

我正在尝试根据多个字段(其中一些字段在引用对象中)对对象列表进行排序。以下代码仅用于说明和示例目的,并非实际代码。AuthorBookStat 这是我要排序的对象(删除了获取器和设置器以增加可读性)

public class AuthorBookStat {
  private String name;
  private AuthorStats authorStats;

}

作者统计

public class AuthorStats {
  private String genre;
  private BookStats bookStats;
}

图书统计

public class BookStats {
  Double averageBookRatings;
  Integer pages;
  String primaryMarket;
}

现在我想首先根据primaryMarket排序,然后是评分,然后是页面,最后是流派

这是我所做的,效果很好

    public class AuthorTest {
      public static void  main(String args[]){
        AuthorBookStat authorBookStat = new AuthorBookStat();
        authorBookStat.setName("A");
    
        AuthorStats authorStats = new AuthorStats();
        authorStats.setGenre("fantasy");
    
        BookStats bookStats = new BookStats();
        bookStats.setAverageBookRatings(3.5d);
        bookStats.setPages(100);
        bookStats.setPrimaryMarket("US");
    
        authorStats.setBookStats(bookStats);
        authorBookStat.setAuthorStats(authorStats);
    
        AuthorBookStat authorBookStat1 = new AuthorBookStat();
        authorBookStat1.setName("A");
    
        AuthorStats authorStats1 = new AuthorStats();
        authorStats1.setGenre("sci-fi");
    
        BookStats bookStats1 = new BookStats();
        bookStats1.setAverageBookRatings(3.5d);
        bookStats1.setPages(100);
        bookStats1.setPrimaryMarket("DE");
    
        authorStats1.setBookStats(bookStats1);
        authorBookStat1.setAuthorStats(authorStats1);
    
        List<AuthorBookStat> authorBookStatList = new ArrayList<>();
        authorBookStatList.add(authorBookStat);
        authorBookStatList.add(authorBookStat1);
    
    
        Comparator<AuthorBookStat> sortByPrimaryMarket =
            Comparator.comparing(a -> a.getAuthorStats().getBookStats().getPrimaryMarket());
        Comparator<AuthorBookStat> sortByRatings =
            Comparator.comparingDouble(a -> a.getAuthorStats().getBookStats().getAverageBookRatings());
        Comparator<AuthorBookStat> sortByPages =
            Comparator.comparingInt(a -> a.getAuthorStats().getBookStats().getPages());
        Comparator<AuthorBookStat> sortByGenre =
            Comparator.comparing(a -> a.getAuthorStats().getGenre());
    
        var sortedList = authorBookStatList
            .stream()
            .sorted(
                sortByPrimaryMarket.thenComparing(sortByRatings)
                    .thenComparing(sortByPages).thenComparing(sortByGenre)).collect(Collectors.toList());
    //    authorBookStatList.sort(sortByPrimaryMarket.thenComparing(sortByRatings)
    //        .thenComparing(sortByPages).thenComparing(sortByGenre));
// I can also sort based on the commented lines above. So both works
        System.out.println(sortedList);
      }
    }

这工作正常,并给了我以下完美的输出

[AuthorBookStat{primaryMarket='DE', ratings=3.5, pages=100, genre=sci-fi},
 AuthorBookStat{primaryMarket='US', ratings=3.5, pages=100, genre=fantasy}]

现在,假设有几个字段为空,并且我有可选的 getter。例如在 Bookstats 评级和 primaryMarket

public Optional<Double> getAverageBookRatings() {
    return Optional.ofNullable(averageBookRatings);
  }
public Optional<String> getPrimaryMarket() {
    return Optional.ofNullable(primaryMarket);
  }

如果有空余的字段首先被认为是一个而其他的不是,我将如何排序。例如,如果主要市场为空,则它获得最后优先级

[AuthorBookStat{primaryMarket='DE', ratings=3.5, pages=100, genre=sci-fi},
 AuthorBookStat{ratings=3.5, pages=100, genre=fantasy}]

标签: javajava-8

解决方案


使用Comparator.nullsFirstor Comparator.nullsLast,您可以指定用于比较键的空安全比较器,考虑到Optional可以使用以下方法返回 null Optional.orElse(null)

Comparator<AuthorBookStat> sortByPrimaryMarket = Comparator
            .comparing(a -> a.getAuthorStats().getBookStats().getPrimaryMarket().orElse(null), Comparator
                    .nullsFirst(String::compareTo));
Comparator<AuthorBookStat> sortByRatings = Comparator
            .comparing(a -> a.getAuthorStats().getBookStats().getAverageBookRatings().orElse(null), Comparator
                    .nullsFirst(Double::compareTo));

推荐阅读