В 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 . |