preface

We usually package some small tools to handle caching or other things. But everyone encapsulates the wheel once and builds the wheel over and over again, which takes a bit of time. Are there any good tool libraries to recommend – Guava. Guava is an open source library that Google encapsulates based on Java. Its performance and usability are better than our own wheels. After all, It is made by Google

  • LoadingCache
  • Multimap and Multiset
  • BiMap
  • The Table (Table).
  • Sets and Maps
  • EventBus
  • StopWatch
  • Files (File operation)
  • RateLimiter
  • Guava Retry

Pay attention to the public account, communicate together, wechat search: sneak forward

Guava’s Maven configuration is introduced

< the dependency > < groupId > com. Google. Guava < / groupId > < artifactId > guava < / artifactId > < version > 27.0 jre < / version > </dependency>Copy the code

LoadingCache

  • LoadingCache is widely used in real-world scenarios. In general, if you encounter scenarios that require a lot of time to calculate or cache values, you should store them in the cache. LoadingCache is similar to ConcurrentMap, but not the same. The big difference is that ConcurrentMap will permanently store all element values until they are displayed and removed, whereas LoadingCache will automatically remove expired values according to the configuration to keep memory usage reasonable
  • In general, Guava Caching is suitable for the following scenarios:
    • Spend some memory in exchange for speed
    • Some keys will be called more than once
    • Cache content is limited and does not exceed the value of memory space. Guava Caches does not store content to files or outside the server. Consider Memcached, Redis, if you have such a need
  • LoadingCache cannot cache null keys
  • CacheBuilder Describes parameters used to construct LoadingCache
CacheBuilder method parameter describe
initialCapacity(int initialCapacity) Initial size of the cache pool
concurrencyLevel(int concurrencyLevel) Setting the number of concurrent requests
maximumSize(long maximumSize) The size of the cache pool. As the cache entries approach this size, Guava begins to reclaim the old cache entries
weakValues() Set the storage reference of value to a virtual reference
softValues() Set the storage reference of value to a soft reference
expireAfterWrite(long duration, TimeUnit unit) Set the time when the object is not written to be removed from memory (irregularly maintained in another thread)
expireAfterAccess(long duration, TimeUnit unit) Set the time when an object is removed from memory without being read/write (irregularly maintained in another thread)
refreshAfterWrite(long duration, TimeUnit unit) Similar to expireAfterWrite, but instead of removing the key immediately, the key is refreshed at the next update, during which time the old value may be returned
removalListener( RemovalListener<? super K1, ? super V1> listener) Listener that is triggered when the cache item is removed
build(CacheLoader<? super K1, V1> loader) If data does not exist, use loader to load data
  • LoadingCache V get(K key)If no value exists for the key, the new value is loaded into the key by calling the load method of CacheLoader
  • The sample
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 {
            returnSystem.currentTimeMillis(); }}); cacheMap.get(1);
Copy the code

Multimap and MultiSet

  • A Multimap can contain multiple values with duplicate keys. You can put multiple values into the same Key without overwriting the previous one
  • The sample
//Multimap: key-value The key and value can 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]
Copy the code
  • One relatively useful scenario for multisets is to keep track of the number of each object, so it can be used for quantitative statistics
  • The sample
//MultiSet: unordered + repeatable count() number of times to get a word
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
Copy the code

BiMap

  • The key and value of BiMap must be unique, and value and key can be exchanged
  • The sample
BiMap<Integer,String> biMap = HashBiMap.create();
biMap.put(1."lwl");
biMap.put(2."csc");
BiMap<String, Integer> map = biMap.inverse(); // Value and key transfer each other
map.forEach((v, k) -> System.out.println(v + "-" + k));
Copy the code

Table

  • Table<R,C,V> table = HashBasedTable.create();As can be seen from the generics, 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 v = table.get(R,C)
  • Traversal data:Set<R> set = table.rowKeySet(); Set<C> set = table.columnKeySet();   
  • The sample
// Map of double keys Map--> Table-->rowKey+columnKey+value
Table<String, String, Integer> tables = HashBasedTable.create();
tables.put("csc"."lwl".1);
//row+column corresponding value
System.out.println(tables.get("csc"."lwl"));
Copy the code

Sets and Maps

// Create an immutable collection
ImmutableList<String> iList = ImmutableList.of("csc"."lwl");
ImmutableSet<String> iSet = ImmutableSet.of("csc"."lwl");
ImmutableMap<String, String> iMap = ImmutableMap.of("csc"."hello"."lwl"."world");
Copy the code

Intersection of sets, union, difference

HashSet setA = newHashSet(1.2.3.4.5);  
HashSet setB = newHashSet(4.5.6.7.8); 
/ / and set
SetView union = Sets.union(setA, setB);   
/ / difference set setA - setB
SetView difference = Sets.difference(setA, setB);  
/ / intersection
SetView intersection = Sets.intersection(setA, setB);  
Copy the code

Map intersection, union, and difference sets

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 has the same entry as mapB
System.out.println(mapDifference.entriesInCommon());
// The 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 entry existsSystem.out.println(mapDifference.entriesOnlyOnRight());; ------------- result ------------- {c=3}
{b=(2.20)}
{a=1}
{d=4}
Copy the code

EventBus

  • EventBus, Guava’s event handling mechanism, is an elegant implementation of the observer pattern (production/consumer programming model) in the design pattern. For event listening and publish subscribe patterns
  • EventBus maintains a Multimap

    , Subscriber> map, key represents the corresponding class of the message (different messages are of different types and different messages are distinguished), value is a Subscriber, Subscriber is actually the corresponding message handler. If there is a message released, find the Subscriber corresponding to the message in this map and execute it
    >
  • Use the sample
@Data
@AllArgsConstructor
public class OrderMessage {
    String message;
}
// Use the @SUBSCRIBE annotation to indicate that the dealWithEvent method is used to process messages corresponding to the OrderMessage type
// Multiple methods can be annotated, and different methods handle 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());
// Publish the message
eventBus.post(new OrderMessage("csc"));
Copy the code

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 runtime:"+nanos);
Copy the code

Files File operation

  • Data is written to
File newFile = new File("D:/text.txt");
Files.write("this is a test".getBytes(), newFile);
// Write again will flush out the previous content
Files.write("csc".getBytes(), newFile);
/ / append to write
Files.append("lwl", newFile, Charset.defaultCharset());
Copy the code
  • Text data reading
File newFile = new File("E:/text.txt");
List<String> lines = Files.readLines(newFile, Charset.defaultCharset());
Copy the code
  • Other operating
methods describe
Files.copy(File from, File to) Copy the file
Files.deleteDirectoryContents(File directory) Delete contents of folders (including files and subfolders)
Files.deleteRecursively(File file) Delete files or folders
Files.move(File from, File to) Move files
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 the file name without the extension
Files.map(File file, MapMode mode) Obtain the memory mapped buffer

RateLimiter

// The RateLimiter constructor, permitsPerSecond
public static RateLimiter create(double permitsPerSecond) 
// permitsPerSecond, warmupPeriod is the initial warm-up time of data, calculated from the first acquire or tryAcquire execution
public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod)
// Get a token, block, return blocking time
public double acquire(a)
Permitting token, block, return block time
public double acquire(int permits)
// Get a token, time out returns
public boolean tryAcquire(Duration timeout)
//// obtains a permitting token, and returns with timeout
public boolean tryAcquire(int permits, Duration timeout)
Copy the code
  • Use the sample
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"); -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 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
Copy the code
  • Because RateLimiter is processed behind time, the first time is zero seconds, no matter how many times
  • It can be seen that acquire took three seconds to warm up data in the first four times, while acquire time tended to be smooth from the fifth to the eighth time

Guava Retry

  • Maven is introduced into
< the dependency > < groupId > com. Making. Rholder < / groupId > < artifactId > guava - retrying < / artifactId > < version > 2.0.0 < / version > </dependency>Copy the code
  • RetryerBuilder constructor
RetryerBuilder method describe
withRetryListener Retry listener
withWaitStrategy Retry interval after a failure
withStopStrategy Stop strategy
withBlockStrategy BlockStrategy BlockStrategy
withAttemptTimeLimiter Execute a time limit policy
retryIfException If an exception occurs, try again
retryIfRuntimeException If a RuntimeException occurs, retry
retryIfExceptionOfType(Class<? extends Throwable> ex) If an EX exception occurs, try again
retryIfException(Predicate<Throwable> exceptionPredicate) Determine whether to retry the exception
retryIfResult(Predicate<V> resultPredicate) Determine 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 calls
retryer.call(() -> true);
Copy the code
  • Spring also has a Retry mechanism. Read about the Retry frameworks Guava-Retry and Spring-Retry

Welcome to correct the errors in the article (the story is pure fiction, if any similarities are pure coincidence)

Refer to the article

  • Introduction and use of the Google Guava utility class
  • Retry frameworks Guava-Retry and Spring-retry
  • Ultra-detailed analysis of the Guava RateLimiter flow limiting principle