В JDK 8 представлены три новых класса : DoubleSummaryStatistics , IntSummaryStatistics и LongSummaryStatistics пакета java.util . Эти классы позволяют быстро и легко вычислить общее количество элементов, минимальное значение элементов, максимальное значение элементов, среднее значение элементов и сумму элементов в коллекции значений типа double, целых или длинных. Документация Javadoc на уровне классов каждого класса начинается с одного и того же предложения, которое кратко излагает это, описывая каждое как «объект состояния для сбора статистики, такой как count, min, max, sum и medium».
Javadoc уровня класса для каждого из этих трех классов также сообщает каждому классу: «Этот класс предназначен для работы (хотя и не требует) с потоками». Наиболее очевидная причина включения этих трех типов классов SummaryStatistics заключается в использовании с потоками , которые также были представлены в JDK 8 .
Действительно, каждый из трех комментариев класса Javadoc на уровне класса также предоставляет пример использования каждого класса в сочетании с потоками соответствующего типа данных. Эти примеры демонстрируют вызов соответствующего метода Streams (Supplier, BiConsumer, BiConsumer) ( операция с изменяемым терминальным потоком ) и передача нового экземпляра класса SummaryStatistics (конструктор), принятие и объединение методов (как ссылки на метод ) в этот метод collect
в качестве аргументов «поставщик», «аккумулятор» и «объединитель» соответственно.
Остальная часть этой статьи демонстрирует использование IntSummaryStatistics
, LongSummaryStatistics
и DoubleSummaryStatistics
. Некоторые из этих примеров будут ссылаться на карту сезонов телесериала «Секретные материалы » и рейтинг Нильсена для премьеры этого сезона. Это показано в следующем листинге кода.
Объявление и инициализация xFilesSeasonPremierRatings
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/** * Maps the number of each X-Files season to the Nielsen rating * (millions of viewers) for the premiere episode of that season. */ private final static Map<Integer, Double> xFilesSeasonPremierRatings; static { final Map<Integer, Double> temporary = new HashMap<>(); temporary.put( 1 , 12.0 ); temporary.put( 2 , 16.1 ); temporary.put( 3 , 19.94 ); temporary.put( 4 , 21.11 ); temporary.put( 5 , 27.34 ); temporary.put( 6 , 20.24 ); temporary.put( 7 , 17.82 ); temporary.put( 8 , 15.87 ); temporary.put( 9 , 10.6 ); xFilesSeasonPremierRatings = Collections.unmodifiableMap(temporary); } |
В следующем листинге кода используется карта, созданная в предыдущем листинге кода, демонстрируется применение DoubleSummaryStatistics
к потоку части «значений» карты, и она очень похожа на примеры, представленные в Javadoc для трех классов SummaryStatistics. Класс DoubleSummaryStatistics
класс IntSummaryStatistics
и класс LongSummaryStatistics
имеют по существу одинаковые поля, методы и API (только различия являются поддерживаемыми типами данных). Поэтому, хотя этот и многие из примеров этого поста специально используют DoubleSummaryStatistics
(поскольку рейтинги Нильсена в X-Files имеют двойные значения), эти принципы применяются к двум другим интегральным типам классов SummaryStatistics.
Использование DoubleSummaryStatistics с потоком на основе коллекции
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/** * Demonstrate use of DoubleSummaryStatistics collected from a * Collection Stream via use of DoubleSummaryStatistics method * references "new", "accept", and "combine". */ private static void demonstrateDoubleSummaryStatisticsOnCollectionStream() { final DoubleSummaryStatistics doubleSummaryStatistics = xFilesSeasonPremierRatings.values().stream().collect( DoubleSummaryStatistics:: new , DoubleSummaryStatistics::accept, DoubleSummaryStatistics::combine); out.println( "X-Files Season Premieres: " + doubleSummaryStatistics); } |
Результат выполнения вышеприведенной демонстрации показан ниже:
1
|
X-Files Season Premieres: DoubleSummaryStatistics{count=9, sum =161.020000, min=10.600000, average=17.891111, max=27.340000} |
В предыдущем примере класс SummaryStatistics применялся к потоку, основанному непосредственно на коллекции (часть «значения» Map
). Следующий листинг кода демонстрирует аналогичный пример, но использует IntSummaryStatistics
и использует промежуточную операцию отображения потока, чтобы указать, какую функцию вызывать для объектов коллекции для заполнения объекта SummaryStatistics. В этом случае для коллекции используется объект Set<Movie>
возвращаемый методом Java8StreamsMoviesDemo.getMoviesSample()
и Java8StreamsMoviesDemo.getMoviesSample()
в моем сообщении блога Stream-Powered Collections Functionality в JDK 8 .
Использование IntSummaryStatistics с картой потока (функция)
01
02
03
04
05
06
07
08
09
10
11
12
13
|
/** * Demonstrate collecting IntSummaryStatistics via mapping of * certain method calls on objects within a collection and using * lambda expressions (method references in particular). */ private static void demonstrateIntSummaryStatisticsWithMethodReference() { final Set<Movie> movies = Java8StreamsMoviesDemo.getMoviesSample(); IntSummaryStatistics intSummaryStatistics = movies.stream().map(Movie::getImdbTopRating).collect( IntSummaryStatistics:: new , IntSummaryStatistics::accept, IntSummaryStatistics::combine); out.println( "IntSummaryStatistics on IMDB Top Rated Movies: " + intSummaryStatistics); } |
Когда приведенная выше демонстрация выполняется, ее вывод выглядит так:
1
|
IntSummaryStatistics on IMDB Top Rated Movies: IntSummaryStatistics{count=5, sum =106, min=1, average=21.200000, max=49} |
До сих пор примеры демонстрировали использование классов SummaryStatistics в их наиболее распространенном случае использования (в сочетании с данными из потоков на основе существующих коллекций). В следующем примере демонстрируется, как можно создать экземпляр DoubleStream с нуля с помощью DoubleStream.Builder, а затем можно вызвать метод summaryStatistics () DoubleStream, чтобы получить экземпляр DoubleSummaryStatistics
.
Получение экземпляра DoubleSummaryStatistics из DoubleStream
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
/** * Uses DoubleStream.builder to build an arbitrary DoubleStream. * * @return DoubleStream constructed with hard-coded doubles using * a DoubleStream.builder. */ private static DoubleStream createSampleOfArbitraryDoubles() { return DoubleStream.builder().add( 12.4 ).add( 13.6 ).add( 9.7 ).add( 24.5 ).add( 10.2 ).add( 3.0 ).build(); } /** * Demonstrate use of an instance of DoubleSummaryStatistics * provided by DoubleStream.summaryStatistics(). */ private static void demonstrateDoubleSummaryStatisticsOnDoubleStream() { final DoubleSummaryStatistics doubleSummaryStatistics = createSampleOfArbitraryDoubles().summaryStatistics(); out.println( "'Arbitrary' Double Statistics: " + doubleSummaryStatistics); } |
Только что перечисленный код производит этот вывод:
1
|
'Arbitrary' Double Statistics: DoubleSummaryStatistics{count=6, sum =73.400000, min=3.000000, average=12.233333, max=24.500000} |
Конечно, подобно только что показанному примеру, IntStream и IntStream.Builder могут предоставлять экземпляр IntSummaryStatistics
а LongStream и LongStream.Builder могут предоставлять экземпляр LongSummaryStatistics
.
Для использования классов SummaryStatistics не нужно иметь поток сбора данных или другой экземпляр BaseStream, поскольку они могут быть созданы непосредственно и использованы непосредственно для предопределенных числовых статистических операций. Следующий листинг кода демонстрирует это путем непосредственного создания экземпляра и последующего DoubleSummaryStatistics
экземпляра DoubleSummaryStatistics
.
Непосредственная реализация DoubleSummaryStatistics
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/** * Demonstrate direct instantiation of and population of instance * of DoubleSummaryStatistics instance. */ private static void demonstrateDirectAccessToDoubleSummaryStatistics() { final DoubleSummaryStatistics doubleSummaryStatistics = new DoubleSummaryStatistics(); doubleSummaryStatistics.accept( 5.0 ); doubleSummaryStatistics.accept( 10.0 ); doubleSummaryStatistics.accept( 15.0 ); doubleSummaryStatistics.accept( 20.0 ); out.println( "Direct DoubleSummaryStatistics Usage: " + doubleSummaryStatistics); } |
Результат выполнения предыдущего листинга кода показан ниже:
1
|
Direct DoubleSummaryStatistics Usage: DoubleSummaryStatistics{count=4, sum =50.000000, min=5.000000, average=12.500000, max=20.000000} |
Как и в предыдущем листинге кода для DoubleSummaryStatistics
, следующий листинг LongSummaryStatistics
непосредственно создает экземпляр LongSummaryStatistics
и заполняет его). Этот пример также демонстрирует, как классы SummaryStatistics предоставляют отдельные методы для запроса отдельной статистики.
Непосредственно создание LongSummaryStatistics / Запрос индивидуальной статистики
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
|
/** * Demonstrate use of LongSummaryStatistics with this particular * example directly instantiating and populating an instance of * LongSummaryStatistics that represents hypothetical time * durations measured in milliseconds. */ private static void demonstrateLongSummaryStatistics() { // This is a series of longs that might represent durations // of times such as might be calculated by subtracting the // value returned by System.currentTimeMillis() earlier in // code from the value returned by System.currentTimeMillis() // called later in the code. LongSummaryStatistics timeDurations = new LongSummaryStatistics(); timeDurations.accept( 5067054 ); timeDurations.accept( 7064544 ); timeDurations.accept( 5454544 ); timeDurations.accept( 4455667 ); timeDurations.accept( 9894450 ); timeDurations.accept( 5555654 ); out.println( "Test Results Analysis:" ); out.println( "\tTotal Number of Tests: " + timeDurations.getCount()); out.println( "\tAverage Time Duration: " + timeDurations.getAverage()); out.println( "\tTotal Test Time: " + timeDurations.getSum()); out.println( "\tShortest Test Time: " + timeDurations.getMin()); out.println( "\tLongest Test Time: " + timeDurations.getMax()); } |
Вывод из этого примера теперь показан:
1
2
3
4
5
6
|
Test Results Analysis: Total Number of Tests: 6 Average Time Duration: 6248652.166666667 Total Test Time: 37491913 Shortest Test Time: 4455667 Longest Test Time: 9894450 |
В большинстве примеров в этой статье я опирался на читаемые реализации toString () классов SummaryStatistics, чтобы продемонстрировать статистику, доступную в каждом классе. Этот последний пример, однако, продемонстрировал, что каждый отдельный тип статистики (количество значений, максимальное значение, минимальное значение, сумма значений и среднее значение) может быть извлечен индивидуально в числовой форме.
Вывод
Независимо от того, предоставляются ли анализируемые данные непосредственно в виде числового потока, предоставляются косвенно через поток коллекции или помещаются вручную в соответствующий экземпляр класса SummaryStatistics, три класса SummaryStatistics могут предоставлять полезные общие статистические вычисления для целых, длинных и двойных чисел.
Ссылка: | Классы JDK 8 SummaryStatistics от нашего партнера JCG Дастина Маркса в блоге Inspired by Actual Events . |