Представление Java 8 потоков и полезных статических / стандартных методов в интерфейсе Comparator позволяет легко сравнивать два объекта на основе значений отдельных полей без необходимости реализации метода сравнения (T, T) для класса, чьи объекты сравниваются ,
Я собираюсь использовать простой класс Song
чтобы помочь продемонстрировать это, и его Song.java
кода Song.java
показан ниже.
Song.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
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
экземпляров песни по порядку, году выпуска, исполнителю и, наконец, альбому.
Сортировка списка песен по году, исполнителю и альбому (в указанном порядке)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
/** * 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()); } |
Вышеприведенный листинг кода был бы несколько менее подробным, если бы я статически импортировал Comparator
и Collectors
, но все же довольно кратко включить эти интерфейсы и имена классов в листинг и, возможно, более полезный для вводного поста в блоге на эту тему.
В приведенном выше листинге кода static default
методы по static default
Comparator.comparingInt и Comparator.thenComparing используются для сортировки потока Song
связанного с базовым List
по году, а затем по исполнителю и, наконец, по альбому. Код хорошо читается и позволяет сравнивать объекты (и результирующую сортировку этих экземпляров) на основе произвольных отдельных методов доступа без необходимости явно указывать Comparator
(естественный порядок сортировки, используемый для каждого сравниваемого результата метода доступа). Обратите внимание: если требуется явный Comparator
, он может быть предоставлен этим static default
методам по static default
через перегруженные методы с тем же именем, которые принимают Comparator
.
Следующий листинг кода — весь демонстрационный класс. Он включает только что показанный метод, а также показывает надуманный пример, составленный из несортированного List
песен.
FineGrainSortingDemo.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
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
).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
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
методов по static default
в интерфейс Comparator
если сравниваемые поля имеют желаемый естественный порядок.
Опубликовано на Java Code Geeks с разрешения Дастина Маркса, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Легкая мелкозернистая сортировка с JDK 8
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |