使用 JDK 8轻松进行细粒度排序

位置:首页>文章>详情   分类: Java教程 > 编程技术   阅读(96)   2024-06-08 16:21:06

Java 8引入了streamsComparator接口static/default方法 span> 可以轻松地根据各个字段的值比较两个对象,而无需在要比较其对象的类上实现 compare(T,T) 方法。

我将使用一个简单的 Song 类来帮助演示这一点,它的 Song.java 代码清单如下所示。 Song.java

package dustin.examples.jdk8;

/**
 * Simple class encapsulating details related to a song
 * and intended to be used for demonstration of JDK 8.
 */
public class Song
{
   /** Song title. */
   private final String title;

   /** Album on which song was originally included. */
   private final String album;

   /** Song's artist. */
   private final String artist;

   /** Year song was released. */
   private final int year;

   /**
    * Constructor accepting this instance's title, artist, and release year.
    *
    * @param newTitle Title of song.
    * @param newAlbum Album on which song was originally included.
    * @param newArtist Artist behind this song.
    * @param newYear Year song was released.
    */
   public Song(final String newTitle, final String newAlbum,
               final String newArtist, final int newYear)
   {
      title = newTitle;
      album = newAlbum;
      artist = newArtist;
      year = newYear;
   }

   public String getTitle()
   {
      return title;
   }

   public String getAlbum()
   {
      return album;
   }

   public String getArtist()
   {
      return artist;
   }

   public int getYear()
   {
      return year;
   }

   @Override
   public String toString()
   {
      return "'" + title + "' (" + year + ") from '" + album + "' by " + artist;
   }
}

刚刚显示的 Song 类缺少 compare 方法,但我们仍然可以很容易地比较 JDK 8 中此类的实例。根据刚刚显示的 Song 的类定义,可以使用以下代码对歌曲实例的 List 进行排序,顺序为发行年份、艺术家,最后专辑。

按年份、艺术家和专辑(按此顺序)对歌曲列表进行排序

/**
 * Returns a sorted version of the provided List of Songs that is
 * sorted first by year of song's release, then sorted by artist,
 * and then sorted by album.
 *
 * @param songsToSort Songs to be sorted.
 * @return Songs sorted, in this order, by year, artist, and album.
 */
private static List<Song> sortedSongsByYearArtistAlbum(
   final List<Song> songsToSort)
{
   return songsToSort.stream()
      .sorted(
         Comparator.comparingInt(Song::getYear)
                   .thenComparing(Song::getArtist)
                   .thenComparing(Song::getAlbum))
      .collect(Collectors.toList());
}

如果我静态导入 ComparatorCollectors,上面的代码清单会稍微不那么冗长,但是包含这些接口仍然相当简洁和类名在列表中,对于关于这个主题的介绍性博客文章可能更有用。

在上面的代码清单中,static default 方法 Comparator.comparingIntComparator.thenComparing 用于对 Song 与底层 $ 按年份关联,然后按艺术家,最后按专辑。该代码具有很高的可读性,并允许基于任意单个访问器方法比较对象(以及对这些实例进行排序),而无需显式指定 List(用于每个比较访问器结果的自然排序顺序) .请注意,如果需要显式 Comparator,可以通过接受 Comparator 的同名重载方法将其提供给这些 static default 方法。

下一个代码清单是整个演示类。它包括刚刚显示的方法,还显示了由歌曲的未排序 List 构造的人为示例。

FineGrainSortingDemo.java

package dustin.examples.jdk8;

import static java.lang.System.out;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Demonstration of easy fine-grained sorting in JDK 8 via
 * stream support for sorting and Comparator's static and
 * default method implementations.
 */
public class FineGrainSortingDemo
{
   /**
    * Construct List of {@code Song}s.
    * 
    * @return Instances of {@code Song}.
    */
   private static List<Song> generateSongs()
   {
      final ArrayList<Song> songs = new ArrayList<>();
      songs.add(
         new Song(
            "Photograph",
            "Pyromania",
            "Def Leppard",
            1983));
      songs.add(
         new Song(
            "Hysteria",
            "Hysteria",
            "Def Leppard",
            1987));
      songs.add(
         new Song(
            "Shout",
            "Songs from the Big Chair",
            "Tears for Fears",
            1984));
      songs.add(
         new Song(
            "Everybody Wants to Rule the World",
            "Songs from the Big Chair",
            "Tears for Fears",
            1985));
      songs.add(
         new Song(
            "Head Over Heels",
            "Songs from the Big Chair",
            "Tears for Fears",
            1985
         ));
      songs.add(
         new Song(
            "Enter Sandman",
            "Metallica",
            "Metallica",
            1991
         )
      );
      songs.add(
         new Song(
            "Money for Nothing",
            "Brothers in Arms",
            "Dire Straits",
            1985
         )
      );
      songs.add(
         new Song(
            "Don't You (Forget About Me)",
            "A Brass Band in African Chimes",
            "Simple Minds",
            1985
         )
      );
      return songs;
   }

   /**
    * Returns a sorted version of the provided List of Songs that is
    * sorted first by year of song's release, then sorted by artist,
    * and then sorted by album.
    *
    * @param songsToSort Songs to be sorted.
    * @return Songs sorted, in this order, by year, artist, and album.
    */
   private static List<Song> sortedSongsByYearArtistAlbum(
      final List<Song> songsToSort)
   {
      return songsToSort.stream()
         .sorted(
            Comparator.comparingInt(Song::getYear)
                      .thenComparing(Song::getArtist)
                      .thenComparing(Song::getAlbum))
         .collect(Collectors.toList());
   }

   /**
    * Demonstrate fine-grained sorting in JDK 8.
    *
    * @param arguments Command-line arguments; none expected.
    */
   public static void main(final String[] arguments)
   {
      final List<Song> songs = generateSongs();
      final List<Song> sortedSongs = sortedSongsByYearArtistAlbum(songs);
      out.println("Original Songs:");
      songs.stream().forEach(song -> out.println("\t" + song));
      out.println("Sorted Songs");
      sortedSongs.forEach(song -> out.println("\t" + song));
   }
}

运行上述代码的输出如下所示,其中列出了使用排序代码后新排序的 Song。值得注意的是,此 stream.sorted() 操作不会更改原始 List(它作用于流而不是 List)。

Original Songs:
 'Photograph' (1983) from 'Pyromania' by Def Leppard
 'Hysteria' (1987) from 'Hysteria' by Def Leppard
 'Shout' (1984) from 'Songs from the Big Chair' by Tears for Fears
 'Everybody Wants to Rule the World' (1985) from 'Songs from the Big Chair' by Tears for Fears
 'Head Over Heels' (1985) from 'Songs from the Big Chair' by Tears for Fears
 'Enter Sandman' (1991) from 'Metallica' by Metallica
 'Money for Nothing' (1985) from 'Brothers in Arms' by Dire Straits
 'Don't You (Forget About Me)' (1985) from 'A Brass Band in African Chimes' by Simple Minds
Sorted Songs
 'Photograph' (1983) from 'Pyromania' by Def Leppard
 'Shout' (1984) from 'Songs from the Big Chair' by Tears for Fears
 'Money for Nothing' (1985) from 'Brothers in Arms' by Dire Straits
 'Don't You (Forget About Me)' (1985) from 'A Brass Band in African Chimes' by Simple Minds
 'Everybody Wants to Rule the World' (1985) from 'Songs from the Big Chair' by Tears for Fears
 'Head Over Heels' (1985) from 'Songs from the Big Chair' by Tears for Fears
 'Hysteria' (1987) from 'Hysteria' by Def Leppard
 'Enter Sandman' (1991) from 'Metallica' by Metallica

JDK 8 引入了流以及接口中的默认方法和静态方法(特别是在本例中的 Comparator 上),这使得在没有任何显式 Comparator的情况下以理想的顺序逐个字段地比较两个对象变得容易 而不是 static default 接口上的预构建 Comparator 方法,如果要比较的字段具有所需的自然顺序。

标签2: Java教程
地址:https://www.cundage.com/article/jcg-easy-fine-grained-sorting-jdk-8.html

相关阅读

Java HashSet 教程展示了如何使用 Java HashSet 集合。 Java哈希集 HashSet 是一个不包含重复元素的集合。此类为基本操作(添加、删除、包含和大小)提供恒定时间性...
SpringApplicationBuilder 教程展示了如何使用 SpringApplicationBuilder 创建一个简单的 Spring Boot 应用程序。 春天 是用于创建企业应...
通道是继 buffers 之后 java.nio 的第二个主要新增内容,我们在之前的教程中已经详细了解了这一点。通道提供与 I/O 服务的直接连接。 通道是一种在字节缓冲区和通道另一端的实体(通...
课程大纲 Elasticsearch 是一个基于 Lucene 的搜索引擎。它提供了一个分布式的、支持多租户的全文搜索引擎,带有 HTTP Web 界面和无模式的 JSON 文档。 Elasti...
解析器是强大的工具,使用 ANTLR 可以编写可用于多种不同语言的各种解析器。 在这个完整的教程中,我们将: 解释基础:什么是解析器,它可以用来做什么 查看如何设置 ANTLR 以便在 Java...
Java 是用于开发各种桌面应用程序、Web 应用程序和移动应用程序的最流行的编程语言之一。以下文章将帮助您快速熟悉 Java 语言,并迈向 API 和云开发等更复杂的概念。 1. Java语言...
Java中的继承是指子类继承或获取父类的所有非私有属性和行为的能力。继承是面向对象编程的四大支柱之一,用于提高层次结构中类之间的代码可重用性。 在本教程中,我们将了解 Java 支持的继承类型,...
Java Message Service 是一种支持正式通信的 API,称为 网络上计算机之间的消息传递。 JMS 为支持 Java 程序的标准消息协议和消息服务提供了一个通用接口。 JMS 提...
之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibern...
Java 项目中的一项常见任务是将日期格式化或解析为字符串,反之亦然。解析日期意味着你有一个代表日期的字符串,例如“2017-08-3”,你想把它转换成一个代表 Java 中日期的对象,例如Ja...