patternjavaMinor
Poor man's lazy evaluation in Java 8
Viewed 0 times
evaluationjavapoorlazyman
Problem
I have an class that cheaply imitates a lazy evaluation scheme. The class is for representing a file and additionally providing meta data on the file. Some of the meta-data can be expensive to evaluate so I only want to evaluate it when requested, and only evaluate it once.
My implementation is such: All private members are stored in an EnumMap and each member is associated with a value in the enum
The values in the EnumMap are Optionals in case evaluation failed (value not in database etc.) Accessors methods get the member by providing the
This is an example of what an accessor looks like.
I am concerned about the unchecked operations in
My implementation is such: All private members are stored in an EnumMap and each member is associated with a value in the enum
Field.private enum Field {
FILE_CODE
//, ...
};
private Map lazyAttributes = new EnumMap(Field.class);The values in the EnumMap are Optionals in case evaluation failed (value not in database etc.) Accessors methods get the member by providing the
Field value associated with the member and a Supplier which will evaluate member if it hasn't yet been evaluated.private Optional lazyLookup(Field field, Supplier> answer) {
if (lazyAttributes.containsKey(field)) { // field was already evaluated, get answer.
return lazyAttributes.get(field); // unchecked Optional to Optional
} else { // field is unevaluated;
Optional result = answer.get(); // evaluate,
lazyAttributes.put(field, result); // then store
return result; // unchecked Optional to Optional
}
}This is an example of what an accessor looks like.
public Optional getFileCode() {
return lazyLookup(Field.FILE_CODE,
() -> FileCodeKeyWords.apply(getName())); // consider this expensive
}I am concerned about the unchecked operations in
lazyLookup and it seems to be an overly complicated setup. I can provide the rest of the class if requested.Solution
Your lazy method is not thread safe. If two threads check for the key at the same time they will both find it absent and both create a new object.
Wrapping your
Wrapping your
EnumMap in a ConcurrentMap will get around this.private ConcurrentMap lazyThreadSafeAttributes = new ConcurrentHashMap(lazyAttributes);
private Optional lazyThreadSafeLookup(Field field, Supplier> answer) {
return lazyThreadSafeAttributes.computeIfAbsent(field, k -> answer.get());
}Code Snippets
private ConcurrentMap<Field, Optional> lazyThreadSafeAttributes = new ConcurrentHashMap(lazyAttributes);
private <T> Optional<T> lazyThreadSafeLookup(Field field, Supplier<Optional<T>> answer) {
return lazyThreadSafeAttributes.computeIfAbsent(field, k -> answer.get());
}Context
StackExchange Code Review Q#114896, answer score: 2
Revisions (0)
No revisions yet.