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.

  • one
    in my opinion, you invent Map.computeIfAbsent . Something like minLengthCache.computeIfAbsent( length, key -> string -> string.length() > key ); - zRrr
  • A. You are right. Now I looked, I really, he is still a bicyclist) But look, in principle, the problem remains, in theory, the class will still be created. So it is not very optimal in that case everything. - Uraty
  • one
    since the function key -> string -> string.length() > key does not capture variables from outside, jvm can optimize it by creating only one instance (just like you save the factory in minLengthConstrain in your answer) - zRrr

2 answers 2

In general, I solved the problem like this:

 private interface ConstrainFactory<C, P> { Constrain<C> create(P param); } private static <P, C> Constrain cachedOrNew(Map<P, Constrain<C>> cache, ConstrainFactory factory, P param) { Constrain cached = cache.get(param); if (cached == null) cache.put(param, cached = factory.create(param)); return cached; } public static Constrain<CharSequence> minLength(int length) { return cachedOrNew(minLengthCache, minLengthConstrain, length); } private static ConstrainFactory<String, Integer> minLengthConstrain = (length) -> (string) -> string.length() > length; 

The whole solution is based on the fact that there is a certain parameter on the basis of which classes can be generated. It will come down for me, but the capabilities of the lambda are in fact not used, and the code looks unique - you cannot enter immediately what you need. Therefore, I leave the question open - can someone prettier offer a solution.

    In general, I tested all this on unpretentious benchmarks. I started the test of 1,000,000 and just counted the total time. Now about the results.

    No optimizations for object cache (To avoid new) are needed. The compiler does it himself, and as it turned out, it works faster than the self-made implementation (for some reason I thought that if I implemented it manually, it would still be faster, and it wouldn’t be like that). Not much of course, but the need to do it manually disappears.

    Optimization of lambda expressions is also not needed. Similarly, the speed of simply creating an object was higher than receiving it through a HashMap and Factory. So one more plus in Java, or rather in the compiler)

    • Why a separate answer? - Nofate
    • Well, both answers are little connected with each other, and the topic is wide enough - Uraty