Last active
April 18, 2018 23:29
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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