I finally found a good use case of Java Local Class
Posted at — 2023-Jun-11
A Basic Problem
Today I needed to come up with a method to mask some certain string (as Apache’s Common Lang’s StringUtils did not support it yet).
The masking logic is simple though:
If the length is smaller than 2, mask everything.
If the length is up to 5, show first and last characters.
If the length is up to 12, show the first two and last two characters.
Otherwise, show the first four and last four characters.
Using Java 17, this is what I came up with:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Rules:
* If it is less than 2, mask everything.
* If 3 <= length < 5, only allow first and last character.
* If 5 <= length <= 12, allow first and last TWO characters.
* If length > 12, allow first and last 4 characters.
*/publicstaticStringmask(Stringstring){if(string==null){returnnull;}if(string.isEmpty()){returnstring;}varlength=string.length();varallowCharacters=length<=2?0:(length<=5?1:(length<=12?2:4));varmaskingCharacter="*";varstart=string.substring(0,allowCharacters);varend=string.substring(length-allowCharacters,length);varmaskedPart=maskingCharacter.repeat(length-allowCharacters*2);returnstart+maskedPart+end;}
The code was pretty simple and straight forward.
How about some “cache” or “memoization”?
Then I thought to myself: “Short strings are pretty common, so the masked parts for length from 1 to 10 could be cached right?”. Let’s try that!
Initially, I came up a solution such that:
In order to define a constant to hold the cache, I needed a class to hold it, hence StringMasker.
I also needed a way to initialize the cache. Here I chose to use a static method instead of doing it directly in static {} initialization block.
The mask() method was changed to incorporate the cached values.
The code worked. However, I didn’t like the fact that I had to introduce one constant and another static method into the enclosing class (whatever that class may be). I wanted the entire implemenation is concealed in one method. I wondered if a method could define a small class within itself just for the sake of holding the constants?
Turned out that it was possible!!! The answer was Java’s Local Classes 1 – Classes defined within a block.
The method could be re-implemented to make it self-contained:
Here I got best of both world, small caching for common masked parts and they are contained inside the method. Another win: JVM only loads the CachingMaskedParts class once.