I have written a class which can time functions, and I'd like to have it reviewed. I'm interested in everything (better naming and commenting, accuracy of measurement, usability, structure, use of lambda, etc.).
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
/**
* A timing class.
*/
public class Timing {
private List<TimingObject> functionsToTime;
private int amount = 1_000_000;
public Timing() {
functionsToTime = new ArrayList<>();
}
/**
* adds a new function which will be timed.
*
* @param <R> return type of functionToTime (irrelevant)
* @param <T> input type of functionToTime (same as return type of
* inputConverter)
* @param functionToTime a function expecting input of type T, returning
* output of any type (R)
* @param inputConverter converts the loop variable to type T and passes it
* to functionToTime
* @param name name of the function (used for output)
*/
public <R, T> void add(Function<R, T> functionToTime, IntFunction<T> inputConverter, String name) {
functionsToTime.add(new TimingObject(functionToTime, inputConverter, name));
}
/**
* sets how often the given functions should be run when timed.
*
* @param amount amount
*/
public void setAmount(int amount) {
this.amount = amount;
}
/**
* performs the actual timing for all given functions.
*/
public void time() {
for (TimingObject timingObject : functionsToTime) {
time(timingObject);
}
}
/**
* passes the result of the timing to the given consumer.
*
* @param consumer consumer
* @param sort how to sort the result
*/
public void output(Consumer<String> consumer, Sort sort) {
switch (sort) {
case ASC:
Collections.sort(functionsToTime,
(TimingObject t1, TimingObject t2) -> (int) (t1.timeTaken - t2.timeTaken));
break;
case DESC:
Collections.sort(functionsToTime,
(TimingObject t1, TimingObject t2) -> (int) (t2.timeTaken - t1.timeTaken));
break;
case NO:
break;
default:
break;
}
consumer.accept(Formater.output(functionsToTime));
}
/**
* times the function in the given object.
*
* @param timingObject timingObject
*/
private void time(TimingObject timingObject) {
runXTimes(timingObject, amount / 100); // warm up
long startTime = System.nanoTime();
runXTimes(timingObject, amount); // actual timing
timingObject.timeTaken = System.nanoTime() - startTime;
}
/**
* runs the function in the given object x amount of times.
*
* @param timingObject timingObject
* @param amount amount
*/
private void runXTimes(TimingObject timingObject, int amount) {
for (int i = 0; i < amount; i++) {
timingObject.function.apply(timingObject.inputConverter.apply(i));
}
}
protected class TimingObject {
private Function function;
private IntFunction inputConverter;
protected String name;
protected long timeTaken;
public TimingObject(Function function, IntFunction inputConverter, String name) {
this.function = function;
this.inputConverter = inputConverter;
this.name = name;
}
}
public static enum Sort {
ASC, DESC, NO
}
}
The formater (not reusable or anything):
import java.util.List;
public class Formater {
/**
* returns name and timeTaken of the given TimingObjects.
*
* The times will be aligned properly.
*
* @param functionsToTime functionsToTime
* @return string
*/
public static String output(List<Timing.TimingObject> functionsToTime) {
int maxNameLength = getMaxNameLength(functionsToTime);
String spaces = getSpaces(maxNameLength) + 1;
StringBuilder out = new StringBuilder();
for (Timing.TimingObject timingObject : functionsToTime) {
out.append(timingObject.name);
out.append(spaces.substring(0, spaces.length() - timingObject.name.length())); // align
out.append(timingObject.timeTaken);
out.append("\n");
}
return out.toString();
}
/**
* returns n spaces.
*
* @param n number of spaces
* @return n spaces
*/
private static String getSpaces(int n) {
StringBuilder spaces = new StringBuilder(n);
for (int i = 0; i < n; i++) {
spaces.append(" ");
}
return spaces.toString();
}
/**
* returns the length of the longest function name.
*
* @return max length
*/
private static int getMaxNameLength(List<Timing.TimingObject> functionsToTime) {
int max = 0;
for (Timing.TimingObject timingObject : functionsToTime) {
int currentLength = timingObject.name.length();
if (timingObject.name.length() > max) {
max = currentLength;
}
}
return max;
}
}
And how it can be used:
import java.util.function.IntFunction;
public class Main {
public static void main(String[] args) {
Timing t = new Timing();
IntFunction<String> intToString = (int i) -> String.valueOf(i) + "test";
IntFunction<Integer> intToInt = (int i) -> i;
// time function string->string:
t.add((String s) -> functionToTimeString(s), intToString, "s + s");
t.add((String s) -> functionToTimeString2(s), intToString, "s + s + s");
// [...]
// we can also time int->int functions at the same time:
t.add((Integer i) -> functionToTimeInt(i), intToInt, "i + i");
t.time();
// output to stdo
t.output((String s) -> System.out.println(s), Timing.Sort.DESC);
}
private static String functionToTimeString(String s) {
return s + s;
}
private static String functionToTimeString2(String s) {
return s + s + s;
}
private static int functionToTimeInt(int i) {
return i + i;
}
}
Output:
s + s + s 121048384
s + s 109057922
i + i 55232562