Skip to content

Instantly share code, notes, and snippets.

@soverby
Last active April 18, 2018 23:29
Show Gist options
  • Save soverby/5a01c8c0b5834bdb23226a6a122875e6 to your computer and use it in GitHub Desktop.
Save soverby/5a01c8c0b5834bdb23226a6a122875e6 to your computer and use it in GitHub Desktop.
Manages one or more timers, I primarily use this for timing code execution.
package com.soverby.test;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static java.lang.String.format;
// Example of using partially applied functions to provide a cleaner way to time method executions or segments
// of code.
public class TimingSupplier {
// Create a customer Functional interface because we don't want to return anything
// and abusing Runnable or something similar smells bad.
// Why could I have used Runnable? Because it only has one method but that method is called
// start, worker.start() is not the appropriate semantic for what the Worker 'does'
@FunctionalInterface
public interface Worker {
public void execute();
}
// Store a map keyed by UUID (the 'ticket' to get your timer back) and a Worker (function)
private static final Map<UUID, Worker> timerStore = new HashMap<>();
// Partially applied function. Snapshots the instant in time it is created
// and creates a new function which has formed a closure on nTim1
// closure capture the *value* (not the reference) of any local variables in-scope at the time
// the closure was created.
// Note - this function is "A Supplier that supplys (returns) a Supplier that itself supplys a Double".
// It can make your brain squirm if you've never seen it before.
// Functions that take or return Functions are also known as higher order functions
public static final Supplier<Supplier<Double>> timingSupplier = () ->
{
double nTime1 = System.nanoTime();
return () -> (System.nanoTime() - nTime1) / 1e6;
};
// Take a Consumer<String> (like logger::info or System.out::println) and the message to print upon completion
public static final UUID timerStart(Consumer<String> logger, String message) {
// Generate the 'ticket' to give back to the consumer
UUID timerUuid = UUID.randomUUID();
// Retrieve the partially applied Supplier function which has a closure around the instant in time
// it was created (now).
Supplier<Double> timerStarted = timingSupplier.get();
// Store a lambda that conforms to the Worker functional interface and itself creates a closure
// on the Supplier we just retrieved keyed by the UUID 'ticket'
// logger.accept: The Worker executes the Consumer<String> function we passed in like log::info
// timerStarted.get(): Execute the partially applied function - which is (System.nanoTime() - nTime1) / 1e6
// Then remove the 'ticket' and its value from the Map.
timerStore.put(timerUuid, () -> {
logger.accept(format(message.conat(": %s"), timerStarted.get()));
timerStore.remove(timerUuid);
});
return timerUuid;
}
// Takes a UUID 'ticket' and executes the Worker function we created and stored in the map above.
// P.S. I wrote this awhile go - the 'containsKey' and 'get' could probably be done more
// expressively
public static final void timerEnd(UUID uuid) {
if (timerStore.containsKey(uuid)) {
timerStore.get(uuid).execute();
}
}
public static void main(String[] args) {
UUID shortTimer = timerStart(System.out::println, "Short timer"); // or logger::info, or any Consumer<String>
UUID longTimer = timerStart(System.out::println, "Long timer");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
timerEnd(shortTimer);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
timerEnd(longTimer);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment