java
47 lines · 8 steps
Detecting calendar conflicts in Java
A sweep-line pass over time-sorted events finds every overlapping pair without comparing all of them.
Explained by
highlit
1public record TimeSlot(LocalDate day, LocalDateTime start, LocalDateTime end) {}
2
3public class ScheduleAnalyzer {
4
5 public record Conflict(CalendarEvent first, CalendarEvent second) {}
6
7 public Map<LocalDate, List<CalendarEvent>> groupByDay(List<CalendarEvent> events) {
8 return events.stream()
9 .collect(Collectors.groupingBy(
10 e -> e.start().toLocalDate(),
11 TreeMap::new,
12 Collectors.toList()));
13 }
14
15 public List<Conflict> findConflicts(List<CalendarEvent> events) {
16 List<CalendarEvent> sorted = events.stream()
17 .sorted(Comparator.comparing(CalendarEvent::start))
18 .toList();
19
20 List<Conflict> conflicts = new ArrayList<>();
21 for (int i = 0; i < sorted.size(); i++) {
22 CalendarEvent current = sorted.get(i);
23 for (int j = i + 1; j < sorted.size(); j++) {
24 CalendarEvent next = sorted.get(j);
25 if (!next.start().isBefore(current.end())) {
26 break;
27 }
28 if (overlaps(current, next)) {
29 conflicts.add(new Conflict(current, next));
30 }
31 }
32 }
33 return conflicts;
34 }
35
36 public Map<LocalDate, List<Conflict>> conflictsByDay(List<CalendarEvent> events) {
37 return findConflicts(events).stream()
38 .collect(Collectors.groupingBy(
39 c -> c.first().start().toLocalDate(),
40 TreeMap::new,
41 Collectors.toList()));
42 }
43
44 private boolean overlaps(CalendarEvent a, CalendarEvent b) {
45 return a.start().isBefore(b.end()) && b.start().isBefore(a.end());
46 }
47}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Sorting events by start time lets you stop scanning as soon as the next event begins after the current one ends.
- 2Records give you concise, immutable value types for domain concepts like a scheduling conflict.
- 3Passing TreeMap::new to groupingBy keeps the resulting map ordered by key for free.
Related explainers
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
java
public static Map<String, String> parseCookieHeader(String header) { Map<String, String> cookies = new LinkedHashMap<>(); if (header == null || header.isBlank()) { return cookies;
Parsing an HTTP Cookie header in Java
string-parsing
http
url-decoding
Intermediate
6 steps
java
public class TimedSocketReader { private static final int READ_TIMEOUT_MS = 5_000; private static final int CONNECT_TIMEOUT_MS = 3_000;
Reading a socket with connect and read timeouts
sockets
timeouts
io
Intermediate
8 steps
python
import re from functools import total_ordering from typing import Optional
Parsing and comparing semantic versions
regex
operator-overloading
sorting
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/detecting-calendar-conflicts-in-java-explained-java-4082/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.