java 50 lines · 9 steps

Computing latency percentiles in Java

An immutable stats class sorts latency samples once, then answers percentile queries with linear interpolation.

Explained by highlit
1import java.util.Arrays;
2import java.util.List;
3 
4public final class LatencyStats {
5 
6 private final long[] sorted;
7 
8 public LatencyStats(List<Long> responseTimesMicros) {
9 this.sorted = responseTimesMicros.stream()
10 .mapToLong(Long::longValue)
11 .sorted()
12 .toArray();
13 }
14 
15 public long percentile(double percentile) {
16 if (percentile < 0.0 || percentile > 100.0) {
17 throw new IllegalArgumentException("percentile must be in [0, 100]");
18 }
19 if (sorted.length == 0) {
20 throw new IllegalStateException("no samples recorded");
21 }
22 if (sorted.length == 1) {
23 return sorted[0];
24 }
25 
26 double rank = percentile / 100.0 * (sorted.length - 1);
27 int lower = (int) Math.floor(rank);
28 int upper = (int) Math.ceil(rank);
29 
30 if (lower == upper) {
31 return sorted[lower];
32 }
33 
34 double weight = rank - lower;
35 return Math.round(sorted[lower] + weight * (sorted[upper] - sorted[lower]));
36 }
37 
38 public long p50() { return percentile(50.0); }
39 
40 public long p95() { return percentile(95.0); }
41 
42 public long p99() { return percentile(99.0); }
43 
44 public long max() { return sorted[sorted.length - 1]; }
45 
46 @Override
47 public String toString() {
48 return "LatencyStats" + Arrays.toString(sorted);
49 }
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Sorting the samples once in the constructor makes every later percentile query cheap.
  2. 2Linear interpolation between neighbouring ranks gives smoother estimates than picking a single element.
  3. 3Validating inputs and edge cases up front keeps the core math simple and safe.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Computing latency percentiles in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code