Multi-stream: sessionize a click feed by inactivity gap

A session is not a field on the event - it is the gap between consecutive events. Sort by time, then start a new bucket whenever the distance from the previous hit exceeds the timeout.

Code
record Hit(String user, int at) {}

var hits = List.of(new Hit("u1", 0), new Hit("u1", 20), new Hit("u1", 400), new Hit("u1", 410));
int gapSeconds = 120;

var sessions = new ArrayList<List<Hit>>();
hits.stream().sorted(Comparator.comparingInt(Hit::at)).forEach(h -> {
    List<Hit> current = sessions.isEmpty() ? null : sessions.get(sessions.size() - 1);
    if (current == null || h.at() - current.get(current.size() - 1).at() > gapSeconds) {
        sessions.add(new ArrayList<>(List.of(h)));
    } else {
        current.add(h);
    }
});

IntStream.range(0, sessions.size()).forEach(k -> System.out.println("session " + (k + 1) + ": "
        + sessions.get(k).stream().map(h -> h.at() + "s").collect(Collectors.joining(", "))));
Output
session 1: 0s, 20s
session 2: 400s, 410s
Advertisement
More in JAVA

Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.

Published 2026-09-20

© Java Coding Hub · About · Contact · Privacy · Terms