001/* 002 * Copyright (C) 2012 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.math; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.base.Preconditions.checkNotNull; 019import static com.google.common.base.Preconditions.checkState; 020import static com.google.common.math.DoubleUtils.ensureNonNegative; 021import static com.google.common.math.StatsAccumulator.calculateNewMeanNonFinite; 022import static com.google.common.primitives.Doubles.isFinite; 023import static java.lang.Double.NaN; 024import static java.lang.Double.doubleToLongBits; 025import static java.lang.Double.isNaN; 026 027import com.google.common.annotations.GwtIncompatible; 028import com.google.common.annotations.J2ktIncompatible; 029import com.google.common.base.MoreObjects; 030import com.google.common.base.Objects; 031import java.io.Serializable; 032import java.nio.ByteBuffer; 033import java.nio.ByteOrder; 034import java.util.Iterator; 035import java.util.stream.Collector; 036import java.util.stream.DoubleStream; 037import java.util.stream.IntStream; 038import java.util.stream.LongStream; 039import org.jspecify.annotations.Nullable; 040 041/** 042 * A bundle of statistical summary values -- sum, count, mean/average, min and max, and several 043 * forms of variance -- that were computed from a single set of zero or more floating-point values. 044 * 045 * <p>There are two ways to obtain a {@code Stats} instance: 046 * 047 * <ul> 048 * <li>If all the values you want to summarize are already known, use the appropriate {@code 049 * Stats.of} factory method below. Primitive arrays, iterables and iterators of any kind of 050 * {@code Number}, and primitive varargs are supported. 051 * <li>Or, to avoid storing up all the data first, create a {@link StatsAccumulator} instance, 052 * feed values to it as you get them, then call {@link StatsAccumulator#snapshot}. 053 * </ul> 054 * 055 * <p>Static convenience methods called {@code meanOf} are also provided for users who wish to 056 * calculate <i>only</i> the mean. 057 * 058 * <p><b>Java 8+ users:</b> If you are not using any of the variance statistics, you may wish to use 059 * built-in JDK libraries instead of this class. 060 * 061 * @author Pete Gillin 062 * @author Kevin Bourrillion 063 * @since 20.0 064 */ 065@J2ktIncompatible 066@GwtIncompatible 067public final class Stats implements Serializable { 068 069 private final long count; 070 private final double mean; 071 private final double sumOfSquaresOfDeltas; 072 private final double min; 073 private final double max; 074 075 /** 076 * Internal constructor. Users should use {@link #of} or {@link StatsAccumulator#snapshot}. 077 * 078 * <p>To ensure that the created instance obeys its contract, the parameters should satisfy the 079 * following constraints. This is the callers responsibility and is not enforced here. 080 * 081 * <ul> 082 * <li>If {@code count} is 0, {@code mean} may have any finite value (its only usage will be to 083 * get multiplied by 0 to calculate the sum), and the other parameters may have any values 084 * (they will not be used). 085 * <li>If {@code count} is 1, {@code sumOfSquaresOfDeltas} must be exactly 0.0 or {@link 086 * Double#NaN}. 087 * </ul> 088 */ 089 Stats(long count, double mean, double sumOfSquaresOfDeltas, double min, double max) { 090 this.count = count; 091 this.mean = mean; 092 this.sumOfSquaresOfDeltas = sumOfSquaresOfDeltas; 093 this.min = min; 094 this.max = max; 095 } 096 097 /** 098 * Returns statistics over a dataset containing the given values. 099 * 100 * @param values a series of values, which will be converted to {@code double} values (this may 101 * cause loss of precision) 102 */ 103 public static Stats of(Iterable<? extends Number> values) { 104 StatsAccumulator accumulator = new StatsAccumulator(); 105 accumulator.addAll(values); 106 return accumulator.snapshot(); 107 } 108 109 /** 110 * Returns statistics over a dataset containing the given values. The iterator will be completely 111 * consumed by this method. 112 * 113 * @param values a series of values, which will be converted to {@code double} values (this may 114 * cause loss of precision) 115 */ 116 public static Stats of(Iterator<? extends Number> values) { 117 StatsAccumulator accumulator = new StatsAccumulator(); 118 accumulator.addAll(values); 119 return accumulator.snapshot(); 120 } 121 122 /** 123 * Returns statistics over a dataset containing the given values. 124 * 125 * @param values a series of values 126 */ 127 public static Stats of(double... values) { 128 StatsAccumulator accumulator = new StatsAccumulator(); 129 accumulator.addAll(values); 130 return accumulator.snapshot(); 131 } 132 133 /** 134 * Returns statistics over a dataset containing the given values. 135 * 136 * @param values a series of values 137 */ 138 public static Stats of(int... values) { 139 StatsAccumulator accumulator = new StatsAccumulator(); 140 accumulator.addAll(values); 141 return accumulator.snapshot(); 142 } 143 144 /** 145 * Returns statistics over a dataset containing the given values. 146 * 147 * @param values a series of values, which will be converted to {@code double} values (this may 148 * cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15)) 149 */ 150 public static Stats of(long... values) { 151 StatsAccumulator accumulator = new StatsAccumulator(); 152 accumulator.addAll(values); 153 return accumulator.snapshot(); 154 } 155 156 /** 157 * Returns statistics over a dataset containing the given values. The stream will be completely 158 * consumed by this method. 159 * 160 * <p>If you have a {@code Stream<Double>} rather than a {@code DoubleStream}, you should collect 161 * the values using {@link #toStats()} instead. 162 * 163 * @param values a series of values 164 * @since 28.2 (but only since 33.4.0 in the Android flavor) 165 */ 166 public static Stats of(DoubleStream values) { 167 return values 168 .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll) 169 .snapshot(); 170 } 171 172 /** 173 * Returns statistics over a dataset containing the given values. The stream will be completely 174 * consumed by this method. 175 * 176 * <p>If you have a {@code Stream<Integer>} rather than an {@code IntStream}, you should collect 177 * the values using {@link #toStats()} instead. 178 * 179 * @param values a series of values 180 * @since 28.2 (but only since 33.4.0 in the Android flavor) 181 */ 182 public static Stats of(IntStream values) { 183 return values 184 .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll) 185 .snapshot(); 186 } 187 188 /** 189 * Returns statistics over a dataset containing the given values. The stream will be completely 190 * consumed by this method. 191 * 192 * <p>If you have a {@code Stream<Long>} rather than a {@code LongStream}, you should collect the 193 * values using {@link #toStats()} instead. 194 * 195 * @param values a series of values, which will be converted to {@code double} values (this may 196 * cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15)) 197 * @since 28.2 (but only since 33.4.0 in the Android flavor) 198 */ 199 public static Stats of(LongStream values) { 200 return values 201 .collect(StatsAccumulator::new, StatsAccumulator::add, StatsAccumulator::addAll) 202 .snapshot(); 203 } 204 205 /** 206 * Returns a {@link Collector} which accumulates statistics from a {@link java.util.stream.Stream} 207 * of any type of boxed {@link Number} into a {@link Stats}. Use by calling {@code 208 * boxedNumericStream.collect(toStats())}. The numbers will be converted to {@code double} values 209 * (which may cause loss of precision). 210 * 211 * <p>If you have any of the primitive streams {@code DoubleStream}, {@code IntStream}, or {@code 212 * LongStream}, you should use the factory method {@link #of} instead. 213 * 214 * @since 28.2 (but only since 33.4.0 in the Android flavor) 215 */ 216 public static Collector<Number, StatsAccumulator, Stats> toStats() { 217 return Collector.of( 218 StatsAccumulator::new, 219 (a, x) -> a.add(x.doubleValue()), 220 (l, r) -> { 221 l.addAll(r); 222 return l; 223 }, 224 StatsAccumulator::snapshot, 225 Collector.Characteristics.UNORDERED); 226 } 227 228 /** Returns the number of values. */ 229 public long count() { 230 return count; 231 } 232 233 /** 234 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 235 * values. The count must be non-zero. 236 * 237 * <p>If these values are a sample drawn from a population, this is also an unbiased estimator of 238 * the arithmetic mean of the population. 239 * 240 * <h3>Non-finite values</h3> 241 * 242 * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it 243 * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the 244 * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values 245 * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}. 246 * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link 247 * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}. 248 * 249 * <p>If you only want to calculate the mean, use {@link #meanOf} instead of creating a {@link 250 * Stats} instance. 251 * 252 * @throws IllegalStateException if the dataset is empty 253 */ 254 public double mean() { 255 checkState(count != 0); 256 return mean; 257 } 258 259 /** 260 * Returns the sum of the values. 261 * 262 * <h3>Non-finite values</h3> 263 * 264 * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it 265 * contains both {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} then the 266 * result is {@link Double#NaN}. If it contains {@link Double#POSITIVE_INFINITY} and finite values 267 * only or {@link Double#POSITIVE_INFINITY} only, the result is {@link Double#POSITIVE_INFINITY}. 268 * If it contains {@link Double#NEGATIVE_INFINITY} and finite values only or {@link 269 * Double#NEGATIVE_INFINITY} only, the result is {@link Double#NEGATIVE_INFINITY}. 270 */ 271 public double sum() { 272 return mean * count; 273 } 274 275 /** 276 * Returns the <a href="http://en.wikipedia.org/wiki/Variance#Population_variance">population 277 * variance</a> of the values. The count must be non-zero. 278 * 279 * <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It 280 * is not guaranteed to return zero when the dataset consists of the same value multiple times, 281 * due to numerical errors. However, it is guaranteed never to return a negative result. 282 * 283 * <h3>Non-finite values</h3> 284 * 285 * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link 286 * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}. 287 * 288 * @throws IllegalStateException if the dataset is empty 289 */ 290 public double populationVariance() { 291 checkState(count > 0); 292 if (isNaN(sumOfSquaresOfDeltas)) { 293 return NaN; 294 } 295 if (count == 1) { 296 return 0.0; 297 } 298 return ensureNonNegative(sumOfSquaresOfDeltas) / count(); 299 } 300 301 /** 302 * Returns the <a 303 * href="http://en.wikipedia.org/wiki/Standard_deviation#Definition_of_population_values"> 304 * population standard deviation</a> of the values. The count must be non-zero. 305 * 306 * <p>This is guaranteed to return zero if the dataset contains only exactly one finite value. It 307 * is not guaranteed to return zero when the dataset consists of the same value multiple times, 308 * due to numerical errors. However, it is guaranteed never to return a negative result. 309 * 310 * <h3>Non-finite values</h3> 311 * 312 * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link 313 * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}. 314 * 315 * @throws IllegalStateException if the dataset is empty 316 */ 317 public double populationStandardDeviation() { 318 return Math.sqrt(populationVariance()); 319 } 320 321 /** 322 * Returns the <a href="http://en.wikipedia.org/wiki/Variance#Sample_variance">unbiased sample 323 * variance</a> of the values. If this dataset is a sample drawn from a population, this is an 324 * unbiased estimator of the population variance of the population. The count must be greater than 325 * one. 326 * 327 * <p>This is not guaranteed to return zero when the dataset consists of the same value multiple 328 * times, due to numerical errors. However, it is guaranteed never to return a negative result. 329 * 330 * <h3>Non-finite values</h3> 331 * 332 * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link 333 * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}. 334 * 335 * @throws IllegalStateException if the dataset is empty or contains a single value 336 */ 337 public double sampleVariance() { 338 checkState(count > 1); 339 if (isNaN(sumOfSquaresOfDeltas)) { 340 return NaN; 341 } 342 return ensureNonNegative(sumOfSquaresOfDeltas) / (count - 1); 343 } 344 345 /** 346 * Returns the <a 347 * href="http://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation"> 348 * corrected sample standard deviation</a> of the values. If this dataset is a sample drawn from a 349 * population, this is an estimator of the population standard deviation of the population which 350 * is less biased than {@link #populationStandardDeviation()} (the unbiased estimator depends on 351 * the distribution). The count must be greater than one. 352 * 353 * <p>This is not guaranteed to return zero when the dataset consists of the same value multiple 354 * times, due to numerical errors. However, it is guaranteed never to return a negative result. 355 * 356 * <h3>Non-finite values</h3> 357 * 358 * <p>If the dataset contains any non-finite values ({@link Double#POSITIVE_INFINITY}, {@link 359 * Double#NEGATIVE_INFINITY}, or {@link Double#NaN}) then the result is {@link Double#NaN}. 360 * 361 * @throws IllegalStateException if the dataset is empty or contains a single value 362 */ 363 public double sampleStandardDeviation() { 364 return Math.sqrt(sampleVariance()); 365 } 366 367 /** 368 * Returns the lowest value in the dataset. The count must be non-zero. 369 * 370 * <h3>Non-finite values</h3> 371 * 372 * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it 373 * contains {@link Double#NEGATIVE_INFINITY} and not {@link Double#NaN} then the result is {@link 374 * Double#NEGATIVE_INFINITY}. If it contains {@link Double#POSITIVE_INFINITY} and finite values 375 * only then the result is the lowest finite value. If it contains {@link 376 * Double#POSITIVE_INFINITY} only then the result is {@link Double#POSITIVE_INFINITY}. 377 * 378 * @throws IllegalStateException if the dataset is empty 379 */ 380 public double min() { 381 checkState(count != 0); 382 return min; 383 } 384 385 /** 386 * Returns the highest value in the dataset. The count must be non-zero. 387 * 388 * <h3>Non-finite values</h3> 389 * 390 * <p>If the dataset contains {@link Double#NaN} then the result is {@link Double#NaN}. If it 391 * contains {@link Double#POSITIVE_INFINITY} and not {@link Double#NaN} then the result is {@link 392 * Double#POSITIVE_INFINITY}. If it contains {@link Double#NEGATIVE_INFINITY} and finite values 393 * only then the result is the highest finite value. If it contains {@link 394 * Double#NEGATIVE_INFINITY} only then the result is {@link Double#NEGATIVE_INFINITY}. 395 * 396 * @throws IllegalStateException if the dataset is empty 397 */ 398 public double max() { 399 checkState(count != 0); 400 return max; 401 } 402 403 /** 404 * {@inheritDoc} 405 * 406 * <p><b>Note:</b> This tests exact equality of the calculated statistics, including the floating 407 * point values. Two instances are guaranteed to be considered equal if one is copied from the 408 * other using {@code second = new StatsAccumulator().addAll(first).snapshot()}, if both were 409 * obtained by calling {@code snapshot()} on the same {@link StatsAccumulator} without adding any 410 * values in between the two calls, or if one is obtained from the other after round-tripping 411 * through java serialization. However, floating point rounding errors mean that it may be false 412 * for some instances where the statistics are mathematically equal, including instances 413 * constructed from the same values in a different order... or (in the general case) even in the 414 * same order. (It is guaranteed to return true for instances constructed from the same values in 415 * the same order if {@code strictfp} is in effect, or if the system architecture guarantees 416 * {@code strictfp}-like semantics.) 417 */ 418 @Override 419 public boolean equals(@Nullable Object obj) { 420 if (obj == null) { 421 return false; 422 } 423 if (getClass() != obj.getClass()) { 424 return false; 425 } 426 Stats other = (Stats) obj; 427 return count == other.count 428 && doubleToLongBits(mean) == doubleToLongBits(other.mean) 429 && doubleToLongBits(sumOfSquaresOfDeltas) == doubleToLongBits(other.sumOfSquaresOfDeltas) 430 && doubleToLongBits(min) == doubleToLongBits(other.min) 431 && doubleToLongBits(max) == doubleToLongBits(other.max); 432 } 433 434 /** 435 * {@inheritDoc} 436 * 437 * <p><b>Note:</b> This hash code is consistent with exact equality of the calculated statistics, 438 * including the floating point values. See the note on {@link #equals} for details. 439 */ 440 @Override 441 public int hashCode() { 442 return Objects.hashCode(count, mean, sumOfSquaresOfDeltas, min, max); 443 } 444 445 @Override 446 public String toString() { 447 if (count() > 0) { 448 return MoreObjects.toStringHelper(this) 449 .add("count", count) 450 .add("mean", mean) 451 .add("populationStandardDeviation", populationStandardDeviation()) 452 .add("min", min) 453 .add("max", max) 454 .toString(); 455 } else { 456 return MoreObjects.toStringHelper(this).add("count", count).toString(); 457 } 458 } 459 460 double sumOfSquaresOfDeltas() { 461 return sumOfSquaresOfDeltas; 462 } 463 464 /** 465 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 466 * values. The count must be non-zero. 467 * 468 * <p>The definition of the mean is the same as {@link Stats#mean}. 469 * 470 * @param values a series of values, which will be converted to {@code double} values (this may 471 * cause loss of precision) 472 * @throws IllegalArgumentException if the dataset is empty 473 */ 474 public static double meanOf(Iterable<? extends Number> values) { 475 return meanOf(values.iterator()); 476 } 477 478 /** 479 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 480 * values. The count must be non-zero. 481 * 482 * <p>The definition of the mean is the same as {@link Stats#mean}. 483 * 484 * @param values a series of values, which will be converted to {@code double} values (this may 485 * cause loss of precision) 486 * @throws IllegalArgumentException if the dataset is empty 487 */ 488 public static double meanOf(Iterator<? extends Number> values) { 489 checkArgument(values.hasNext()); 490 long count = 1; 491 double mean = values.next().doubleValue(); 492 while (values.hasNext()) { 493 double value = values.next().doubleValue(); 494 count++; 495 if (isFinite(value) && isFinite(mean)) { 496 // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15) 497 mean += (value - mean) / count; 498 } else { 499 mean = calculateNewMeanNonFinite(mean, value); 500 } 501 } 502 return mean; 503 } 504 505 /** 506 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 507 * values. The count must be non-zero. 508 * 509 * <p>The definition of the mean is the same as {@link Stats#mean}. 510 * 511 * @param values a series of values 512 * @throws IllegalArgumentException if the dataset is empty 513 */ 514 public static double meanOf(double... values) { 515 checkArgument(values.length > 0); 516 double mean = values[0]; 517 for (int index = 1; index < values.length; index++) { 518 double value = values[index]; 519 if (isFinite(value) && isFinite(mean)) { 520 // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15) 521 mean += (value - mean) / (index + 1); 522 } else { 523 mean = calculateNewMeanNonFinite(mean, value); 524 } 525 } 526 return mean; 527 } 528 529 /** 530 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 531 * values. The count must be non-zero. 532 * 533 * <p>The definition of the mean is the same as {@link Stats#mean}. 534 * 535 * @param values a series of values 536 * @throws IllegalArgumentException if the dataset is empty 537 */ 538 public static double meanOf(int... values) { 539 checkArgument(values.length > 0); 540 double mean = values[0]; 541 for (int index = 1; index < values.length; index++) { 542 double value = values[index]; 543 if (isFinite(value) && isFinite(mean)) { 544 // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15) 545 mean += (value - mean) / (index + 1); 546 } else { 547 mean = calculateNewMeanNonFinite(mean, value); 548 } 549 } 550 return mean; 551 } 552 553 /** 554 * Returns the <a href="http://en.wikipedia.org/wiki/Arithmetic_mean">arithmetic mean</a> of the 555 * values. The count must be non-zero. 556 * 557 * <p>The definition of the mean is the same as {@link Stats#mean}. 558 * 559 * @param values a series of values, which will be converted to {@code double} values (this may 560 * cause loss of precision for longs of magnitude over 2^53 (slightly over 9e15)) 561 * @throws IllegalArgumentException if the dataset is empty 562 */ 563 public static double meanOf(long... values) { 564 checkArgument(values.length > 0); 565 double mean = values[0]; 566 for (int index = 1; index < values.length; index++) { 567 double value = values[index]; 568 if (isFinite(value) && isFinite(mean)) { 569 // Art of Computer Programming vol. 2, Knuth, 4.2.2, (15) 570 mean += (value - mean) / (index + 1); 571 } else { 572 mean = calculateNewMeanNonFinite(mean, value); 573 } 574 } 575 return mean; 576 } 577 578 // Serialization helpers 579 580 /** The size of byte array representation in bytes. */ 581 static final int BYTES = (Long.SIZE + Double.SIZE * 4) / Byte.SIZE; 582 583 /** 584 * Gets a byte array representation of this instance. 585 * 586 * <p><b>Note:</b> No guarantees are made regarding stability of the representation between 587 * versions. 588 */ 589 public byte[] toByteArray() { 590 ByteBuffer buff = ByteBuffer.allocate(BYTES).order(ByteOrder.LITTLE_ENDIAN); 591 writeTo(buff); 592 return buff.array(); 593 } 594 595 /** 596 * Writes to the given {@link ByteBuffer} a byte representation of this instance. 597 * 598 * <p><b>Note:</b> No guarantees are made regarding stability of the representation between 599 * versions. 600 * 601 * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as 602 * {@link ByteOrder#LITTLE_ENDIAN}, to which a BYTES-long byte representation of this instance 603 * is written. In the process increases the position of {@link ByteBuffer} by BYTES. 604 */ 605 void writeTo(ByteBuffer buffer) { 606 checkNotNull(buffer); 607 checkArgument( 608 buffer.remaining() >= BYTES, 609 "Expected at least Stats.BYTES = %s remaining , got %s", 610 BYTES, 611 buffer.remaining()); 612 buffer 613 .putLong(count) 614 .putDouble(mean) 615 .putDouble(sumOfSquaresOfDeltas) 616 .putDouble(min) 617 .putDouble(max); 618 } 619 620 /** 621 * Creates a Stats instance from the given byte representation which was obtained by {@link 622 * #toByteArray}. 623 * 624 * <p><b>Note:</b> No guarantees are made regarding stability of the representation between 625 * versions. 626 */ 627 public static Stats fromByteArray(byte[] byteArray) { 628 checkNotNull(byteArray); 629 checkArgument( 630 byteArray.length == BYTES, 631 "Expected Stats.BYTES = %s remaining , got %s", 632 BYTES, 633 byteArray.length); 634 return readFrom(ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN)); 635 } 636 637 /** 638 * Creates a Stats instance from the byte representation read from the given {@link ByteBuffer}. 639 * 640 * <p><b>Note:</b> No guarantees are made regarding stability of the representation between 641 * versions. 642 * 643 * @param buffer A {@link ByteBuffer} with at least BYTES {@link ByteBuffer#remaining}, ordered as 644 * {@link ByteOrder#LITTLE_ENDIAN}, from which a BYTES-long byte representation of this 645 * instance is read. In the process increases the position of {@link ByteBuffer} by BYTES. 646 */ 647 static Stats readFrom(ByteBuffer buffer) { 648 checkNotNull(buffer); 649 checkArgument( 650 buffer.remaining() >= BYTES, 651 "Expected at least Stats.BYTES = %s remaining , got %s", 652 BYTES, 653 buffer.remaining()); 654 return new Stats( 655 buffer.getLong(), 656 buffer.getDouble(), 657 buffer.getDouble(), 658 buffer.getDouble(), 659 buffer.getDouble()); 660 } 661 662 private static final long serialVersionUID = 0; 663}