In general, there is such a code:
private static final Map<Integer, Constrain<CharSequence>> minLengthCache = new HashMap<>(), maxLengthCache = new HashMap<>(); public static Constrain<CharSequence> minLength(int length) { Constrain<CharSequence> cached = minLengthCache.get(length); if (cached == null) minLengthCache.put(length, cached = string -> string.length() > length); return cached; } public static Constrain<CharSequence> maxLength(int length) { Constrain<CharSequence> cached = maxLengthCache.get(length); if (cached == null) maxLengthCache.put(length, cached = string -> string.length() < length); return cached; } As you can see, it is very ugly repeated. What causes a lot of dangers to make mistakes with copy-paste, and if there are 20 such functions and you need to change something, then you can even be killed against the wall.
The first thing that comes to mind is this:
public static Constrain<CharSequence> minLength(int length) { return cachedOrNew(string -> string.length() > length); } public static Constrain<CharSequence> cachedOrNew(Constrain<CharSequence> newObj) { Constrain<CharSequence> cached = minLengthCache.get(length); if (cached == null) minLengthCache.put(length, cached = newObj); return cached; } But here the cache is completely lost. After all, every time there will still be a new instance of the object, and at the same time its class, the object that must be returned if there is no such thing in the cache.
In principle, I can imagine how this can be solved through the nested class, .Class and reflection, but then you have to abandon the very convenient syntax of lambda expressions.
Map.computeIfAbsent. Something likeminLengthCache.computeIfAbsent( length, key -> string -> string.length() > key );- zRrrkey -> string -> string.length() > keydoes not capture variables from outside, jvm can optimize it by creating only one instance (just like you save the factory inminLengthConstrainin your answer) - zRrr