Tools: introduce several easy-to-use guava tool classes

Posted by xconspirisist on Sat, 29 Jan 2022 11:27:24 +0100

preface

Coupon website https://www.cps3.cn/

We usually encapsulate some processing cache or other gadgets. But it takes a little time for everyone to package once and build the wheel again and again. Is there any good tool library recommended - guava. Guava is an open source library encapsulated by Google based on java. Its performance and practicability are better than our own wheels. After all, it is produced by Google. Here are some commonly used guava tools

  • LoadingCache (local cache)
  • Multimap and Multiset
  • BiMap
  • Table
  • Sets and Maps
  • EventBus (event)
  • StopWatch
  • Files
  • RateLimiter
  • Guava Retry

Pay attention to the official account and exchange with each other. Search by WeChat: Sneak ahead.

Introduction of maven configuration in guava

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.0-jre</version>
 </dependency>

LoadingCache

  • LoadingCache is widely used in actual scenarios. Generally, if you encounter a scenario that requires a lot of time to calculate or cache values, you should save the values to the cache. LoadingCache is similar to ConcurrentMap, but different. The biggest difference is that ConcurrentMap will permanently store all element values until they are removed, but LoadingCache will automatically remove the expired values according to the configuration in order to maintain reasonable memory use
  • In general, Guava caching is applicable to the following scenarios:
    • Spend some memory in exchange for speed
    • Some key s will be called more than once
    • The cache content is limited and will not exceed the value of memory space. Guava caches will not store the content to files or outside the server. If there is such a demand, consider using memcached and redis
  • LoadingCache cannot cache null key s
  • Introduction to the LoadingCache parameter of CacheBuilder construction
CacheBuilder method parametersdescribe
initialCapacity(int initialCapacity)Initial size of the cache pool
concurrencyLevel(int concurrencyLevel)Set concurrent number
maximumSize(long maximumSize)The size of the cache pool. When the cache item is close to this size, Guava starts to recycle the old cache item
weakValues()Set the storage reference of value to be a virtual reference
softValues()The storage reference that sets value is a soft reference
expireAfterWrite(long duration, TimeUnit unit)If the set time object is not written, the object will be deleted from memory (maintained irregularly in another thread)
expireAfterAccess(long duration, TimeUnit unit)If the set time object is not accessed by read / write, the object will be deleted from memory (maintained irregularly in another thread)
refreshAfterWrite(long duration, TimeUnit unit)It is similar to expireAfterWrite, but instead of removing the key immediately, it will be refreshed at the next update, during which the old value may be returned
removalListener( RemovalListener<? super K1, ? super V1> listener)Listener, triggered when the cache item is removed
build(CacheLoader<? super K1, V1> loader)When the data does not exist, the loader is used to load the data
  • Loadingcache V get (k key) to get the cache value. If the key does not have a value, it will call the load method of CacheLoader to load the new value into the key
  • Examples
LoadingCache<Integer,Long> cacheMap = CacheBuilder.newBuilder().initialCapacity(10)
    .concurrencyLevel(10)
    .expireAfterAccess(Duration.ofSeconds(10))
    .weakValues()
    .recordStats()
    .removalListener(new RemovalListener<Integer,Long>(){
        @Override
        public void onRemoval(RemovalNotification<Integer, Long> notification) {
            System.out.println(notification.getValue());
        }
    })
    .build(new CacheLoader<Integer,Long>(){
        @Override
        public Long load(Integer key) throws Exception {
            return System.currentTimeMillis();
        }
    });
cacheMap.get(1);

Multimap and MultiSet

  • The feature of Multimap is that it can contain values with several duplicate keys. It can put into multiple different values but the same key, but it will not overwrite the previous content
  • Examples
//Multimap: key value key can be repeated, and value can also be repeated
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("csc","1");
multimap.put("lwl","1");
multimap.put("csc","1");
multimap.put("lwl","one");
System.out.println(multimap.get("csc"));
System.out.println(multimap.get("lwl"));
---------------------------
[1, 1]
[1, one]
  • MultiSet has a relatively useful scene, which is to track the number of each object, so it can be used for quantity statistics
  • Examples
//MultiSet: the number of times the unordered + repeatable count() method obtains words enhances readability + simple operation
Multiset<String> set = HashMultiset.create();
set.add("csc");
set.add("lwl");
set.add("csc");
System.out.println(set.size());
System.out.println(set.count("csc"));
---------------------------
3
2

BiMap

  • The key of BiMap must be unique, and the value must also be unique. The mutual conversion of value and key can be realized
  • Examples
BiMap<Integer,String> biMap = HashBiMap.create();
biMap.put(1,"lwl");
biMap.put(2,"csc");
BiMap<String, Integer> map = biMap.inverse(); // value and key switch to each other
map.forEach((v, k) -> System.out.println(v + "-" + k));

Table

  • Table<R,C,V> table = HashBasedTable. create();, It can be seen from the generics that the table is determined by the double primary key R (row) and C (column), and V is the stored value
  • New data: table put(R,C,V)
  • Get data: v = table get(R,C)
  • Traversal data: set < R > set = table rowKeySet(); Set<C> set = table. columnKeySet();   
  • Examples
// Double key map -- > table -- > rowkey + columnkey + value  
Table<String, String, Integer> tables = HashBasedTable.create();
tables.put("csc", "lwl", 1);
//value corresponding to row+column
System.out.println(tables.get("csc","lwl"));

Sets and Maps

// Creation of immutable sets
ImmutableList<String> iList = ImmutableList.of("csc", "lwl");
ImmutableSet<String> iSet = ImmutableSet.of("csc", "lwl");
ImmutableMap<String, String> iMap = ImmutableMap.of("csc", "hello", "lwl", "world");

Intersection, union and difference of set

HashSet setA = newHashSet(1, 2, 3, 4, 5);  
HashSet setB = newHashSet(4, 5, 6, 7, 8); 
//Union
SetView union = Sets.union(setA, setB);   
//Difference seta setb
SetView difference = Sets.difference(setA, setB);  
//intersection
SetView intersection = Sets.intersection(setA, setB);  

Intersection, union, difference set of map

HashMap<String, Integer> mapA = Maps.newHashMap();
mapA.put("a", 1);mapA.put("b", 2);mapA.put("c", 3);
HashMap<String, Integer> mapB = Maps.newHashMap();
mapB.put("b", 20);mapB.put("c", 3);mapB.put("d", 4);
MapDifference<String, Integer> mapDifference = Maps.difference(mapA, mapB);
//mapA and mapB have the same entry
System.out.println(mapDifference.entriesInCommon());
//mapA and mapb keys have the same value and different entries
System.out.println(mapDifference.entriesDiffering());
//Only mapA entries exist
System.out.println(mapDifference.entriesOnlyOnLeft());
//Only mapB entries exist
System.out.println(mapDifference.entriesOnlyOnRight());;
-------------result-------------
{c=3}
{b=(2, 20)}
{a=1}
{d=4}

EventBus

  • EventBus is Guava's event processing mechanism and an elegant implementation of observer mode (production / consumer programming model) in design mode. For event listening and publish subscribe mode
  • The internal implementation principle of EventBus is not complex, and a Multimap < class <? > will be maintained in EventBus, Subscriber > map, key represents the class corresponding to the message (different messages, different classes, different messages). value is a subscriber, and the subscriber is actually the corresponding message handler. If a message is published, go to the map to find the subscriber corresponding to the message for execution
  • Use example
@Data
@AllArgsConstructor
public class OrderMessage {
    String message;
}
//The @ Subscribe annotation indicates that the dealWithEvent method is used to process the message corresponding to the OrderMessage type
//Multiple methods can be annotated, and different methods deal with different object messages
public class OrderEventListener {
    @Subscribe
    public void dealWithEvent(OrderMessage event) {
        System.out.println("Content:" + event.getMessage());
    }
}
-------------------------------------
// new AsyncEventBus(String identifier, Executor executor);
EventBus eventBus = new EventBus("lwl"); 
eventBus.register(new OrderEventListener());
// Release news
eventBus.post(new OrderMessage("csc"));

StopWatch

Stopwatch stopwatch = Stopwatch.createStarted();
for(int i=0; i<100000; i++){
    // do some thing
}
long nanos = stopwatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("Logical code running time:"+nanos);

Files file operation

  • Data writing
File newFile = new File("D:/text.txt");
Files.write("this is a test".getBytes(), newFile);
//Writing again will erase the previous content
Files.write("csc".getBytes(), newFile);
//Append write
Files.append("lwl", newFile, Charset.defaultCharset());
  • Text data reading
File newFile = new File("E:/text.txt");
List<String> lines = Files.readLines(newFile, Charset.defaultCharset());
  • Other operations
methoddescribe
Files.copy(File from, File to)Copy file
Files.deleteDirectoryContents(File directory)Delete the contents under the folder (including files and subfolders)
Files.deleteRecursively(File file)Delete files or folders
Files.move(File from, File to)move file
Files.touch(File file)Create or update the timestamp of the file
Files.getFileExtension(String file)Gets the extension of the file
Files.getNameWithoutExtension(String file)Gets a file name without an extension
Files.map(File file, MapMode mode)Get memory mapping buffer

RateLimiter

//RateLimiter construction method, current limiting permitsPerSecond per second
public static RateLimiter create(double permitsPerSecond) 
//Current limiting permitsPerSecond and warmupPeriod per second are the initial warm-up time of data, which are calculated from the first acquisition or tryAcquire
public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod)
//Get a token, block and return the blocking time
public double acquire()
//Get permits tokens, block and return blocking time
public double acquire(int permits)
//Get a token and return after timeout
public boolean tryAcquire(Duration timeout)
obtain permits Tokens, timeout return
public boolean tryAcquire(int permits, Duration timeout)
  • Use example
RateLimiter limiter = RateLimiter.create(2, 3, TimeUnit.SECONDS);
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
---------------  result -------------------------
get one permit cost time: 0.0s
get one permit cost time: 1.331672s
get one permit cost time: 0.998392s
get one permit cost time: 0.666014s
get one permit cost time: 0.498514s
get one permit cost time: 0.498918s
get one permit cost time: 0.499151s
get one permit cost time: 0.488548s
  • Because RateLimiter lags behind processing, the first time no matter how much is taken is zero seconds
  • You can see that the first four acquires took three seconds to warm up the data, and the time spent in the fifth to eighth acquires tended to be smooth

Guava Retry

  • maven introduction
<dependency>
  <groupId>com.github.rholder</groupId>
  <artifactId>guava-retrying</artifactId>
  <version>2.0.0</version>
</dependency>
  • RetryerBuilder construction method
RetryerBuilder methoddescribe
withRetryListenerRetry listener
withWaitStrategyRetry interval after failure
withStopStrategyStop strategy
withBlockStrategyBlocking strategy
withAttemptTimeLimiterExecution time limit policy
retryIfExceptionIf an exception occurs, try again
retryIfRuntimeExceptionIf a RuntimeException occurs, try again
retryIfExceptionOfType(Class<? extends Throwable> ex)If an ex exception occurs, try again
retryIfException(Predicate<Throwable> exceptionPredicate)Judge whether to retry the exception
retryIfResult(Predicate<V> resultPredicate)Judge whether to retry the returned result
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
    .retryIfException()
    .retryIfResult(Predicates.equalTo(false))
    .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS))
    .withStopStrategy(StopStrategies.stopAfterAttempt(5))
    .build();
//Retryer call                
retryer.call(() -> true);
  • Spring also has a corresponding retry mechanism. For related articles, you can see the retry framework guava retry and spring retry
    Welcome refers to the error in the text (the story is purely fictional, and if there is any similarity, it is purely coincidental)

Reference articles

  • Introduction and use of Google guava tool class
  • Retry frameworks guava retry and spring retry
  • Ultra detailed analysis of Guava RateLimiter current limiting principle