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